# Best Practice / Resources for Blade

**URL:** https://discourse.roots.io/t/best-practice-resources-for-blade/8341
**Category:** sage
**Tags:** sage9, blade
**Created:** 2016-12-16T20:07:36Z
**Posts:** 180

## Post 1 by @smutek — 2016-12-16T20:07:36Z

I noticed that Laravel Blade has been added to Sage 9. It seems like it’s going to be pretty great but I’m wondering if anyone has any tips or resources for using Blade with WordPress. I’ve hit the Laravel docs and also have a Laracasts subscription.

I mean, I get the concepts, but I’d love to see some real world examples as they pertain to WordPress. I was checking out [WP Blade](https://github.com/tormjens/wp-blade) to get some ideas but, again, I’m just not sure what best practice is.

I tried creating a directive for custom queries but ultimately I felt like I was still cluttering the top of my page templates (views?) with a bunch of logic, just using a different syntax.

Anyway, I realize my post is a little scattered. Short of it is I’m pretty excited to get into Blade templates and would love to hear any thoughts, tips, or ideas for using Blade with WordPress. The more logic I can get out of my template files the happier I’ll be. It’s one of my biggest gripes when building with WordPress.

:smile:

---

## Post 2 by @darjanpanic — 2016-12-16T20:59:18Z

As much as I know from learning Laravel in the last weeks this one can be good for starting out - [https://laracasts.com/series/laravel-5-fundamentals/episodes/5](https://laracasts.com/series/laravel-5-fundamentals/episodes/5)

But as you said we may need some pointers or good docs for that with examples for best practices :slight_smile:

---

## Post 3 by @kalenjohnson — 2016-12-16T22:23:35Z

So what you may have noticed with many of the other templating engine integrations, they are much more than just allowing new templates. Timber for instance comes as almost a framework, with controllers and a new router.

The thinking process for integrating Blade into Sage was really to make it as light and drop-in as possible. We made sure to have the template hierarchy work the same, and we’ve squashed some bugs related to third party plugin templates.

We haven’t even really included many Blade directives. I’ve seen directives for WP\_Query as well as ACF, and those can be helpful, but again not something that necessarily needs to be in a starter theme.

It should be relatively simple, but open ended to add in a controller like system. My thought was it could be similar to controller’s in other frameworks, however instead of returning a view with data passed to it, you can just filter the view data: [https://github.com/roots/sage/blob/6ca3b3faa7e3ec29d01016fdc7bd656ff0e8a64e/src/filters.php#L50](https://github.com/roots/sage/blob/6ca3b3faa7e3ec29d01016fdc7bd656ff0e8a64e/src/filters.php#L50)

With all that in mind, we will be writing a blog post pretty soon to cover Blade, let us know what you’d like to know about it.

---

## Post 4 by @masoninthesis — 2016-12-19T04:07:46Z

@smutek, I’ve been thinking the same thing since I saw it added.

I’m a big fan of Tuts+, and I saw they have [a course](https://code.tutsplus.com/courses/getting-started-with-laravel-4/lessons/blade-essentials) that covers blade essentials, layouts, and partials. Only problem is that it’s specifically for Laravel. I’ll probably watch it through.

I watched [one on youtube](https://www.youtube.com/watch?v=nABYejAhdVA), and I just found [a scotch.io article on it](https://scotch.io/tutorials/simple-laravel-layouts-using-blade). They usually have some good content.

@kalenjohnson, one specific question I’ve been wondering is, “couldn’t I do all of this stuff with React?”. What would be the pros/cons of Blade vs. React?

---

## Post 5 by @ben — 2016-12-19T05:43:54Z

> [@masoninthesis](#):
>
> @kalenjohnson, one specific question I’ve been wondering is, “couldn’t I do all of this stuff with React?”. What would be the pros/cons of Blade vs. React?

Let’s keep this thread on topic — Blade resources and best practices, not why we’re using PHP instead of JS :slight_smile:

---

## Post 6 by @smutek — 2016-12-19T07:58:45Z

> [@kalenjohnson](#):
>
> With all that in mind, we will be writing a blog post pretty soon to cover Blade, let us know what you’d like to know about it.

Awesome! I think I’m mainly looking for how best to do things like… everything! :slight_smile:

Mostly best practices, I think. For example, I was looking at WP Blade and was thinking it looked good but then saw [this comment on the Blade PR](https://github.com/roots/sage/pull/1765#issuecomment-265267297) referring to those directives as “Bad”, so I wonder - what is bad about them?

@darjanpanic and @masoninthesis, thanks for the links. I have a Laracasts subscription and will be giving it more attention, and will check out the Tuts+ and other links as well.

---

## Post 7 by @masoninthesis — 2016-12-19T08:28:15Z

Fair enough @ben! It was an out there question. I just like to learn as few frameworks as possible, and given that I’ve already invested time into learning React, I guess I’m actually just questioning if Blade is going to stick around long enough to make it worth learning.

Obviously blade and React serve different needs (single pg apps vs. templating) So instead of React vs. Blade- @kalenjohnson, I guess I’m asking:

What are some specific, basic examples of how it can make PHP dev easier?

Why is blade useful to learn?

Is it’s implementation pretty long term?

And, what are the basics someone should know to be able to implement it?

Thanks guys! I’m genuinely stoked to get up and running w/ Sage9

---

## Post 8 by @smutek — 2017-01-12T02:12:22Z

I was playing around a little tonight and was able to return data to my page template. I’d love some feedback on this if anyone has time.

Okay, so I have 2 pages, titled “post-1” and post-2", and both pages are using a custom page template. In this case I’m using the default custom page template that ships with Sage, and I’ve made a partial called content-page-custom.blade.php

I also have a file I’ve added to `/src/` called controllers.php, in which I have the follwing -

```
namespace App;

function post1()
{
    $data = [
        'title' => 'List',
        'names' => [
            'Frank',
            'Bob',
            'Mary'
        ]
    ];

    return $data;
}

add_filter( 'sage/template/post-1/data', 'App\\post1' );

function post2()
{
    $data = [
        'title' => 'List 2',
        'names' => [
            'Bill',
            'Sally',
            'Becky'
        ]
    ];

    return $data;
}

add_filter( 'sage/template/post-2/data', 'App\\post2' );

function both()
{
    $data = ['both' => 'Both'];
    // Undefined, gets overwritten
    return $data;
}

add_filter( 'sage/template/page-template-template-custom-blade/data', 'App\\both' );
```

Then, on my partial I have -

```
<h2>{{ $title or 'Not Defined' }}</h2>

<ul>
  @foreach($names as $name)
    <li>{{$name}}</li>
  @endforeach
</ul>

<h2>{{ $both or 'Not defined' }}</h2>
```

The lists output as expected, with post-1 getting the correct data back for the post-1 filter, and post 2 getting the correct data back as well.

The `both()` function should return identical data to both pages, and is hooked into `page-template-template-custom-blade`, but gets overwritten because it fires earlier and `$data` it’s in the same scope as the lists.

So… questions… :slight_smile:

Am I on the right track here?  
What’s the best way to avoid having my variables overwritten, like in my `both()` example?  
It seems that whatever I save in the `$data` variable has to be saved in key value pairs, right?

Any feedback would be most appreciated, I feel like I’m pretty close to understanding this.

---

## Post 9 by @kalenjohnson — 2017-01-12T03:47:09Z

Keep in mind that filter is a standard WP filter, so just like any other filter, you need to accept the original data/variable, modify it, and return it.

```
function both($data) {
    $data['both'] = 'Both';

    return $data;
}
```

Other than that, it looks good. That is basically what I had in mind if I was going to implement some simple controllers in Sage 9

---

## Post 10 by @smutek — 2017-01-12T04:30:36Z

Got it, thank you Kalen!

---

## Post 11 by @smutek — 2017-01-12T06:22:53Z

Wow, this is super nice man, fantastic job!

Here’s a simple image slider with Slick. This is using [ACF’s gallery field](https://www.advancedcustomfields.com/add-ons/gallery-field/), but anything will do.

Controller -

```
function slider( $data ) {

    $images = get_field('images');

    if ( $images ) {
        $data['images'] = $images;
    }

    return $data;
}
add_filter( 'sage/template/home/data', 'App\\slider' );
```

View -

```
<ul class="list-unstyled slider">
  @forelse($images as $image)
    <li><img src="{{$image['url']}}" alt="{{$image['alt']}}"></li>
  @empty
    <li class="alert alert-danger">No Images</li>
  @endforelse
</ul>
```

I’m giddy about this, it’s like a whole new WordPress!!! :sunny: :smile: :sunny:

---

## Post 12 by @smutek — 2017-01-12T06:35:12Z

You can even split it out and put the slider in it’s own little blade file, and have something like this -

```
@php(the_content())

@if($images)
  @include('partials/slider')
@endif
```

Sorry for all the posts, but this is so damn nice!

---

## Post 13 by @Twansparant — 2017-01-12T09:55:29Z

Interesting stuff indeed! I might ditch Timber for this after all :slight_smile:

I was just wundering how you guys would declare global data, regardless of the body class?  
Stuff like menu’s, languages, ACF options etc?

> [@Disable Blade in favor of Timber?](https://discourse.roots.io/t/disable-blade-in-favor-of-timber/8505/9):
>
> Ah cool, that DOES look very interesting! I was wundering how you can declare global data (such as menu’s etc), regardless of the body class? Can you use some kind of wildcard or are you supposed to add a global body class and then use the filter on that? Something like this: base.blade.php: \<body @php(body\_class('global'))\> controllers.php: function globalData() { $main\_menu = wp\_get\_nav\_menu\_items('Primary Navigation'); if ($main\_menu) { $data['main\_menu'] = $main\_menu; } return $d…

---

## Post 14 by @smutek — 2017-01-13T19:31:44Z

Hey, check this one out for navs –

```
/**
 * Navigation arguments
 *
 * @param $data
 *
 * @return mixed
 */
function navControl( $data ) {

    // Pass the walker class to a var, so it
    // doesn't instantiate here.
    $bootstrapWalker = 'wp_bootstrap_navwalker';

    // Main Nav
    $mainNavArgs = [
        'theme_location' => 'primary_navigation',
        'walker' => new $bootstrapWalker,
        'menu_class' => 'navbar-nav mr-auto'
    ];

    $data['mainNavArgs'] = $mainNavArgs;

    // Social Nav
    $socialNavArgs = [
        'walker' => new $bootstrapWalker,
        'theme_location' => 'social_navigation',
        'menu_class' => 'nav social-nav',
        'link_before' => '<span class="sr-only">',
        'link_after' => '</span>'
    ];

    $data['socialNavArgs'] = $socialNavArgs;

    return $data;

}

add_filter( 'sage/template/global/data', 'App\\navControl' );
```

The project I’m working on now has 2 navs, this changes the nav calls in my template file from this -

```
<div class="collapse navbar-collapse" id="navbarSupportedContent">
    @if (has_nav_menu('primary_navigation'))
      {!! wp_nav_menu(['theme_location' => 'primary_navigation', 'walker' => new wp_bootstrap_navwalker(), 'menu_class' => 'navbar-nav mr-auto']) !!}
    @endif
  </div>
```

to this -

```
<div class="collapse navbar-collapse" id="navbarSupportedContent">
    @if (has_nav_menu('primary_navigation'))
      {!! wp_nav_menu($mainNavArgs) !!}
    @endif
</div>
```

:slight_smile: Much cleaner!

I just added a body class called `global` so I can access it everywhere.

---

## Post 15 by @MWDelaney — 2017-01-13T21:26:20Z

Man I am struggling to understand this, but I think I get it. This keeps the ugly (and duplicative if you’re calling it twice on a page) `wp_nav_menu()` arguments out of the template file, making everything easier to read. Then passes that args array to the template for use in `$mainNavArgs`.

Sort of like globaling the args in `functions.php` but not horrifying.

Is that close at least?

---

## Post 16 by @smutek — 2017-01-13T21:36:13Z

That’s the benefit for me, with the nav. It makes the markup cleaner and helps separate concerns a little more.

This is still new to me as well, maybe the nav example is overkill, but I’m almost certain to get obsessive and go overboard a little before I find some balance. :slight_smile:

---

## Post 17 by @MWDelaney — 2017-01-16T19:35:13Z

OK so I implemented your Nav directive just to get comfortable with it. It works!

It seems like this could be a really easy way to go overboard and over-design a system, though. Instead of calling a WP function, I’m calling a function that calls that function. Is that better?

---

## Post 18 by @smutek — 2017-01-16T20:32:06Z

For me I guess it’s going to come down to moving logic outside of template files and also readability. For example, the social nav in my project would look like this -

```
{!! wp_nav_menu(['walker' => new bootstrapWalker, 'theme_location' => 'social_navigation', 'menu_class' => 'nav social-nav', 'link_before' => '<span class="sr-only">', 'link_after' => '</span>']) !!}
```

So when I look at that I feel like, man that’s kind of unruly, and I can simplify that to -

```
{!! wp_nav_menu($socialNavArgs) !!}
```

Which is much more readable to me and seems a good use.

I guess it _could_ go a step further and move the nav menu call out as well, but personally I don’t mind the function call, so long as it’s paired down to a simple, meaningful expression when used inside a template file.

With this the intent is clear - give me the social nav:

```
{!! wp_nav_menu($socialNavArgs) !!}
```

I couldn’t see myself abstracting something like `the_post()` out of a template file for the exact reasons you mentioned. It doesn’t really make sense and seems like adding unnecessary complexity.

Does that make sense? Personally I’m stoked to be able to get logic out of my template files, and make template files more readable.

---

## Post 19 by @christianmagill — 2017-01-23T23:46:32Z

I’m really liking the ideas in this thread!

Is there any way to get the results of the standard WP\_Query for a view into a variable? I’d rather loop through posts with standard blade syntax.

I know I can requery entirely with get\_posts() but I’m wondering if there’s a way to get a similar data return for the default query on a view.

Has anyone played around with this? How deep of a rabbit hole is it to go down?

Thanks,

---

## Post 20 by @joaovpmamede — 2017-02-02T22:03:53Z

Would love to add [Blade SVG](https://github.com/adamwathan/blade-svg) to my next Sage websites but I might have to read and get more comfortable with Blade.

Anyone knows if this is possible to begin with?

Edit: I guess this one is really tied to Laravel so it won’t work.  
There’s always [https://packagist.org/packages/oscarotero/inline-svg](https://packagist.org/packages/oscarotero/inline-svg) which works really well.

---

## Post 21 by @MWDelaney — 2017-02-03T05:25:10Z

Having worked with this, mostly from @smutek’s examples, for a couple weeks now, it seems to me that the best use of Blade’s additional functionality is to provide context for templates.

The rabbit hole goes as deep as you want, since it’s just php, but the goal (in my mind) should be to remove complexity rather than to add it in all cases.

So for instance, with Sage 9’s implementation of Blade, let’s say you use the thumbnail size featured image on your archive template, but the medium size on your single. With the right directive you could call `the_post_thumbnail($AllTheRightArguments)` on both templates and let your directive set up the context based on which template is being used. This simplifies the template file itself and centralizes the context creation so it can be updated easily.

This is a round about way of saying that the test should be “does this simplify things, or am I inventing complexity?”. I fail this test two out of three times but I’m trying to get better :slight_smile:

---

## Post 22 by @Log1x — 2017-02-04T20:22:29Z

Just chiming in to thank @smutek for the controller.php idea. Now my views are even cleaner!

:smiley: :smiley: :smiley:

Example:

**src/controller.php**

```
<?php

namespace App;

/**
 * Home
 */
function home()
{
    $data = [
        'steps' => [
            'Idea' => 'icon-light-bulb',
            'Plan' => 'icon-pencil',
            'Design' => 'icon-laptop',
            'Develop' => 'icon-code',
            'Stage' => 'icon-bug',
            'Deploy' => 'icon-rocket'
        ]
    ];

    return $data;
}

add_filter('sage/template/home/data', 'App\\home');

?>
```

**templates/partials/content-page-home.blade.php**

```
<ol>
  @foreach ($steps as $title => $icon)
    <li>
      <div class="step">
        <i class="icon {{ $icon }}"></i>
        <span class="title">{{ $loop->iteration }}. {{ $title }}</span>
        @if ($loop->first or $loop->last)
          <span class="dot"></span>
        @endif
      </div>
      @if (!$loop->last)
        @if ($loop->iteration % 2 == 0)
          <i class="icon icon-arrow-long-up"></i>
        @else
          <i class="icon icon-arrow-long-down"></i>
        @endif
      @endif
    </li>
  @endforeach
</ol>
```

…now that is some clean markup! Also loving Blade’s auto-creation of the `$loop` variable.

[![](https://log1x.com/screenshots/2017-02-04_15-36-25_SpKN3.png) ](https://log1x.com/screenshots/2017-02-04_15-36-25_SpKN3.png)

Looking forward to living my new site with Sage 9. :slight_smile:

---

## Post 23 by @bsilva — 2017-02-05T03:56:32Z

This is very neat. Where are you guys putting your controller.php file? With the specific template file as outlined in the filter name? Are using one controller for each page or one controller to rule all pages?

Also doesn’t the PSR-4 spec recommend `\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>` format? I’m still learning PSR-4 so I was just curious to why you weren’t approaching it that way rather than stay valid with the spec requirements.

---

## Post 24 by @Log1x — 2017-02-05T10:19:54Z

Mine is simply in `src/controller.php` for now and then added to the `array_map` in `functions.php`:

`['helpers', 'setup', 'filters', 'admin', 'controller']`

I plan on pulling the data from my theme options panel so the above is just an example. I don’t plan on actually hardcoding the values there such as my array of `steps`.

As far as the namespaces, I was a little curious about that too. I’m just sticking with `App` for now to make it uniform with how the rest of Sage is setup. Maybe one of the devs can chime in and clear that up.

---

## Post 25 by @Log1x — 2017-02-05T11:23:42Z

This is in reply to @christianmagill’s question up above…

Not 100% what you were asking, but perhaps Blade directives are what you’re looking for?

Here’s some quick and dirty examples to maybe spark some ideas from the rest of the community who may or may not know about these.

**src/setup.php** [Line 150](https://github.com/roots/sage/blob/master/src/setup.php#L150)

```
/**
 * Create @posts Blade directive
 */
sage('blade')->compiler()->directive('posts', function () {
    return '<?php while(have_posts()) : the_post(); ?>';
});

/**
 * Create @endposts Blade directive
 */
sage('blade')->compiler()->directive('endposts', function () {
    return '<?php endwhile; ?>';
});

/**
 * Create @query() Blade directive
 */
sage('blade')->compiler()->directive('query', function ($args) {
    $output = '<?php $bladeQuery = new WP_Query($args); ?>';
    $output .= '<?php while ($bladeQuery->have_posts()) : ?>';
    $output .= '<?php $bladeQuery->the_post(); ?>';

    return $output;
});

/**
 * Create @endquery Blade directive
 */
sage('blade')->compiler()->directive('endquery', function () {
    return '<?php endwhile; ?>';
});

/**
 * Create @title Blade directive
 */
sage('blade')->compiler()->directive('title', function () {
    return '<?php the_title(); ?>';
});

/**
 * Create @content Blade directive
 */
sage('blade')->compiler()->directive('content', function () {
    return '<?php the_content(); ?>';
});

/**
 * Create @excerpt Blade directive
 */
sage('blade')->compiler()->directive('excerpt', function () {
    return '<?php the_excerpt(); ?>';
});
```

**Example Usage:**

**Usage for @query()**

```
@php
  $args = array(
    'author' => 1
  );
@endphp

@query($args)
  <h2>@title</h2>
  @excerpt
@endquery
```

**Usage for @posts**

```
@posts
  <h2>@title</h2>
  @content
@endposts
```

These were done very quickly as an example and I’m sure could be improved on for real world usage.

Looking forward to seeing if anyone comes up with some other nice directives. I created an issue on the tracker about them at some point but the Sage dev’s wanted to keep their side of the things as clean as possible, but that doesn’t mean a plugin isn’t out of the question with adding some clean, well written directives to help make views even more pleasant.

By default, Sage is equipped with the `@asset()` directive to help link to various assets within’ your views. This is specifically useful for when using `yarn run build:production` as it will add cache busting to all of your filenames, so simply hardlinking them will cause them to break.

I’m sure this subject will be touched on significantly as Sage 9 gets out of beta and proper documentation is released.

---

## Post 26 by @smutek — 2017-02-05T11:48:25Z

Regarding the PSR-4 spec, I’m not entirely sure how the guts of this work but I think that this is being handled by the Laravel components. Note that the files in `sage\src\lib\Sage` all use fully qualified namespaces.

Check out the Laravel docs on application structure - [Application Structure - Laravel 5.0 - The PHP Framework For Web Artisans](https://laravel.com/docs/5.0/structure)

Here’s the relevant bit -

> The “meat” of your application lives in the` app` directory. By default, this directory is namespaced under `App` and is autoloaded by Composer using the [PSR-4 autoloading standard](http://www.php-fig.org/psr/psr-4/).

---

## Post 27 by @smutek — 2017-02-05T11:50:50Z

> [@Log1x](#):
>
> Mine is simply in src/controller.php for now and then added to the array\_map in functions.php:

Doing the same here. :slight_smile:

---

## Post 28 by @smutek — 2017-02-05T12:02:05Z

@Log1x - Hey, these directives are great . Thanks for sharing them! I’d tried putting some together a couple weeks back but wasn’t making much progress.

---

## Post 29 by @Log1x — 2017-02-05T13:52:09Z

:slight_smile:

The possibilities are endless, really.

[https://laracasts.com/discuss/channels/laravel/useful-blade-directives](https://laracasts.com/discuss/channels/laravel/useful-blade-directives) has some great examples of non-wordpress related directives such as `@set`, `@varDump`, etc.

In their examples, simply replace `Blade::directive` with `sage('blade')->compiler()->directive`.

Also, I mentioned it in another thread, but thought I’d also include here that you can also share variables such as `$GLOBALS` to all of your blade views so you don’t have to call them manually.

**Example**

```
/**
 * Share variables to Blade views
 */
sage('blade')->share('options', $GLOBALS['options']);
sage('blade')->share('shortcodes', $GLOBALS['shortcode_tags']);
```

and just like that, `$options` and `$shortcodes` are now available in your views.

```
<ul>
  @foreach (array_keys($shortcodes) as $shortcode)
    <li>[{{ $shortcode }}]</li>
  @endforeach
</ul>
```

I found this especially useful when using an options framework such as Redux and them having all of the data stored in a global variable. It was obnoxious to have to global the variable every time I needed to use it. This is much more convenient. :wink:

---

## Post 30 by @mensch — 2017-02-05T20:36:21Z

This is really cool and like @Twansparant I’m seriously thinking of dumping Timber for a pure Blade setup in combination with directives and a data controller.

Is there a way to move the directives to a separate PHP file? I’m not sure how to reference the Sage compiler using the `sage` function in helpers.php. When adding directives.php to the `array_map` function in `functions.php` a fatal error occurs as Illuminate cannot find the `sage.blade` class. For some reason this isn’t the problem when adding the directives to setup.php.

---

## Post 31 by @Log1x — 2017-02-05T20:50:18Z

What’s your `directives.php` look like so far? Are you using the `App` namespace?

If not, try using `\App\sage('blade')` instead.

---

## Post 32 by @swalkinshaw — 2017-02-05T20:59:16Z

You probably know this, but we can simplify this even further:

```
<?php

namespace App;

/**
 * Home
 */
add_filter('sage/template/home/data', function() {
    return [
        'steps' => [
            'Idea' => 'icon-light-bulb',
            'Plan' => 'icon-pencil',
            'Design' => 'icon-laptop',
            'Develop' => 'icon-code',
            'Stage' => 'icon-bug',
            'Deploy' => 'icon-rocket'
        ]
    ]; 
});

?>
```

---

## Post 33 by @Log1x — 2017-02-05T21:00:43Z

Knew that, but didn’t think of it. I will go that route instead. Thanks!

---

## Post 34 by @mensch — 2017-02-05T21:02:28Z

I’m using the namespace and using it without the namespace (so `\App\sage('blade')`) throws the same error unfortunately. This is what my directives.php looks like currently.

```
<?php

namespace App;

/**
 * Create @title Blade directive
 */
sage('blade')->compiler()->directive('title', function () {
    return '<?php the_title(); ?>';
});
```

The error is an uncaught `ReflectionException`:  
`Uncaught exception 'ReflectionException' with message 'Class sage.blade does not exist' in /Path/to/web/app/themes/sage/vendor/illuminate/container/Container.php:749`

---

## Post 35 by @Log1x — 2017-02-05T21:04:32Z

Gotcha.

Assuming adding:

```
use Roots\Sage\Template\Blade;
use Roots\Sage\Template\BladeProvider;
```

will do the trick.

If not, I will post a fix once I’m on my computer.

---

## Post 36 by @mensch — 2017-02-05T21:12:57Z

I was messing with those imports as well (copy pasted the Blade ones from setup.php). Adding the following (or just the two you mentioned) doesn’t help, unfortunately:

```
use Roots\Sage\Config;
use Roots\Sage\Template\Blade;
use Roots\Sage\Template\BladeProvider;
```

---

## Post 37 by @Log1x — 2017-02-05T21:15:32Z

```
<?php

namespace App;

add_action('after_setup_theme', function () {
    /**
     * Create @title Blade directive
     */
    sage('blade')->compiler()->directive('title', function () {
        return '<?php the_title(); ?>';
    });
});

?>
```

Here you go. :slight_smile:

---

## Post 38 by @mensch — 2017-02-05T21:21:45Z

Thanks for the help, it’s working now! I feel rather stupid, because after reviewing setup.php more closely I noticed that Blade is also referenced in the `after_setup_theme` action using the `sage('blade')` function. :neutral_face:

---

## Post 39 by @Log1x — 2017-02-05T21:22:18Z

Hah. Don’t worry, I overlooked it too at first.

---

## Post 40 by @Log1x — 2017-02-06T17:43:21Z

Played around with ACF Pro for the first time. Here’s some directives I came up with:

```
/**
 * Advanced Custom Fields Blade directives
 */

/**
 * Create @fields() Blade directive
 */
sage('blade')->compiler()->directive('fields', function ($expression) {
    $expression = strtr($expression, array('(' => '', ')' => ''));
    $output = "<?php if (have_rows($expression)) : ?>";
    $output .= "<?php while (have_rows($expression)) : ?>";
    $output .= "<?php the_row(); ?>";
    return $output;
});

/**
 * Create @endFields Blade directive
 */
sage('blade')->compiler()->directive('endFields', function () {
    return "<?php endwhile; endif; ?>";
});

/**
 * Create @field() Blade directive
 */
sage('blade')->compiler()->directive('field', function ($expression) {
     $expression = strtr($expression, array('(' => '', ')' => ''));
     return "<?php the_field($expression); ?>";
});

/**
 * Create @getField() Blade directive
 */
sage('blade')->compiler()->directive('getField', function ($expression) {
    $expression = strtr($expression, array('(' => '', ')' => ''));
    return "<?php get_field($expression); ?>";
});

/**
 * Create @hasField() Blade directive
 */
sage('blade')->compiler()->directive('hasField', function ($expression) {
    $expression = strtr($expression, array('(' => '', ')' => ''));
    return "<?php if (get_field($expression)) : ?>";
});

/**
 * Create @endField Blade directive
 */
sage('blade')->compiler()->directive('endField', function () {
    return "<?php endif; ?>";
});

/**
 * Create @sub() Blade directive
 */
sage('blade')->compiler()->directive('sub', function ($expression) {
    $expression = strtr($expression, array('(' => '', ')' => ''));
    return "<?php the_sub_field($expression); ?>";
});

/**
 * Create @getSub() Blade directive
 */
sage('blade')->compiler()->directive('getSub', function ($expression) {
    $expression = strtr($expression, array('(' => '', ')' => ''));
    return "<?php get_sub_field($expression); ?>";
});

/**
 * Create @hasSub() Blade directive
 */
sage('blade')->compiler()->directive('hasSub', function ($expression) {
    $expression = strtr($expression, array('(' => '', ')' => ''));
    return "<?php if (get_sub_field($expression)) : ?>";
});

/**
 * Create @endSub Blade directive
 */
sage('blade')->compiler()->directive('endSub', function () {
    return "<?php endif; ?>";
});
```

**@fields() Usage**

```
<ul>
  @fields('links')
    @hasSub('title')
      <li>@sub('title')</li>
    @endSub

    @hasSub('url')
      <li>@sub('url')</li>
    @endSub
  @endFields
</ul>
```

**@field() Usage**

```
@hasField('test')
  @field('test')
@endField
```

Not shown in my example is `@getSub()` and `@getField()` allowing you to return the values instead of echoing them.

Shoutout to @Daniel_Willitzer for providing me with ACF Pro so I could create these.

Any suggestions/modifications are welcome. I made these in the last 15 minutes and this is the first time I’ve ever used ACF, so there may be a more effective way to do these.

One thing would be to combine `@hasField` and `@endField` to make it a bit easier in certain use cases. The main reason I separated them were for styling purposes (i.e. wrapping `@field()` in `<li></li>`– obviously you don’t want the markup appearing if it doesn’t exist…)

I also learned that you have to strip the parenthesis when passing an `$expression` to a Blade directive. Kind of strange… This makes `array`'s a little hard to accomplish. For that, it looks like the common thing to do is pass an array with comma’s and then `explode` the `$expression` variable and using it inside of the directive such as `$expression = explode(',', $expression)`. You can see a few examples [here](https://laracasts.com/discuss/channels/laravel/useful-blade-directives) of people doing that.

It’s not pretty, but in this case where I’m only passing string’s I simply did:

`$expression = strtr($expression, array('(' => '', ')' => ''));`

That being said, I will probably refactor the other directives I posted a few posts up to accommodate this.

---

## Post 41 by @smutek — 2017-02-07T01:04:40Z

Hey that’s really nice man. The only thing I would do differently would be to pull the `if` and `endif` statements out. So you could, for example -

```
@ifhaverows('links')
  <ul>
  @fields('links')
    ...
  @endFields
  </ul>
@endif
```

---

## Post 42 by @smutek — 2017-02-07T01:32:12Z

Here’s another way to do a simple repeater w/o custom directives. :slight_smile:

```
@if (have_rows('list'))
  <ul>
    @while(have_rows('list')) @php(the_row())
      <li>@php(the_sub_field('list_item'))</li>
    @endwhile
  </ul>
@endif
```

(nothing against custom directives, mind you)

---

## Post 43 by @MWDelaney — 2017-02-07T01:36:31Z

This makes more sense to me. The directive method just looks like rewriting ACF with slightly fewer characters.

That sounded mean. I don’t intend it to be mean. I think this stuff is super great but there’s a point where you’re rewriting WordPress with different function names.

---

## Post 44 by @Log1x — 2017-02-07T11:28:42Z

I agree it’s not the most sane thing in some cases.

I did it more so as a proof of concept kinda thing. I’m not personally using it in the theme I’m working on right now, but it was a good learning experience for figuring our how Blade handles `$expression`.

---

## Post 45 by @kaisermann — 2017-02-07T17:35:22Z

So, let’s say that I need to get the current template name (in my case, it’s for the `data-namespace` attribute used by [Barba.js](http://barbajs.org). Is the `sage/template/global/data` filter technique the only way?

Thanks :slight_smile:

---

## Post 46 by @smutek — 2017-02-07T17:58:23Z

Hey @Log1x - it’s definitely helpful. I don’t recall exactly what it was, but there was something I was trying to setup a couple weeks back that threw me for a loop. I believe it was an ACF repeater field with post objects, or maybe I was trying to set up a custom directive - I don’t remember - but it was the way `$expression` is used that I wasn’t getting.

Thanks!

---

## Post 47 by @smutek — 2017-02-07T18:08:02Z

Are you trying to get the current template while inside of a function? If so can you use `is_page_template()`?

If you need the results available to any page template then the global technique is the only way I know of.

---

## Post 48 by @kaisermann — 2017-02-07T19:19:32Z

Nope. I need it in the `base.blade.php` file.

This is what I’m currently doing:

**templates/layouts/base.blade.php** :

```
...
	<div id="page-wrapper" role="document">
		<div class="page-container" data-namespace="{!! $current_template !!}">
			....			
		</div>
	</div>
...
```

**src/controller.php:**

```
add_filter( 'sage/template/global/data', function( $data, $template ) {
	return [
		'current_template' => basename( $template ,'.blade.php' ),
	];
}, 10, 2 );
```

---

## Post 49 by @smutek — 2017-02-07T20:20:26Z

Got it! Yeah man, that’s probably the way I’d go about it as well.

---

## Post 50 by @vdrnn — 2017-02-14T08:37:23Z

I’m using the ACF’s flexible content field.

I have a `content-page.blade.php` within the partials folder which looks like this:

```
@if(have_rows('inhaltselemente'))
  @while (have_rows('inhaltselemente')) @php(the_row())
    @if (get_row_layout() == 'title_and_content')

      @include('partials/content-element-title-and-text')

    @elseif (get_row_layout() == 'dividing_line')

      @include('partials/content-element-dividing-line')

    @endif
  @endwhile
@else
  // no layouts found
@endif
```

Here I’ll have around 10 different layouts for the user to choose in the admin area.

My `content-element-title-and-text.blade.php` looks like this:

```
<section class="content-element-title-text container-fluid {{ $title_text_background_color }}">
  <div class="row">
    <div class="container">
      <div class="row">
        <header>
          @if ( get_sub_field('hide_title') === false )
            @if (get_sub_field('headline_size') === '1')
              <h1 class="headline-1">
                {{ the_sub_field('title') }}
              </h1>
            @elseif (get_sub_field('headline_size') === '2')
              <h2 class="headline-2">
                {{ the_sub_field('title') }}
              </h2>
            @elseif (get_sub_field('headline_size') === '3')
              <h3 class="headline-3">
                {{ the_sub_field('title') }}
              </h3>
            @endif
          @endif
          <p class="lauftext">
            {{ the_sub_field('content') }}
          </p>
        </header>
      </div>
    </div>
  </div>
</div>
```

Now I wonder what the best way is to build the controller (`src/controller.php`) in order to serve the data to the template respectively for the different layouts.  
I started like this:

```
function acf_data( $data ) {
    if( have_rows('inhaltselemente') ):
        while ( have_rows('inhaltselemente') ) : the_row();
            if( get_row_layout() == 'title_and_content' ):
                $data['title_text_background_color'] = get_sub_field('background_color');
            elseif( get_row_layout() == 'download' ):
                $data['download'] = get_sub_field('file');
            endif;
        endwhile;
    endif;
    return $data;
}
add_filter( 'sage/template/page/data', 'App\\acf_data' );
```

So I add the data for each layout that I need.  
However, if I have more than 1 content elements of the same type in the backend, I only get the last `get_sub_field('background_color')` value for example.

In general, is there a better approach for this? Or am I missing a detail?  
Here’s a screenshot of the admin to get an idea: [https://cl.ly/2a3a2X0E4613](https://cl.ly/2a3a2X0E4613)

Any hints appreciated :slight_smile:

---

## Post 51 by @vdrnn — 2017-02-14T10:49:47Z

Solved it now with a quick’n’dirty solution.  
I’m simply iterating over my while loop in the controller and in the content-page.blade.php template.

**controller:**

```
function acf_data( $data ) {
    if( have_rows('inhaltselemente') ):
        $row = 0;
        while ( have_rows('inhaltselemente') ) : the_row();
            if( get_row_layout() == 'title_and_content' ):
                $data['title_text_background_color'][$row] = get_sub_field('background_color');
            elseif( get_row_layout() == 'download' ):
                $data['download'] = get_sub_field('file');
            endif;
            $row++;
        endwhile;
    endif;
    return $data;
}
add_filter( 'sage/template/page/data', 'App\\acf_data' );
```

**content-page.blade.php**

```
@if(have_rows('inhaltselemente'))
  <?php $row = 0; ?>
  @while (have_rows('inhaltselemente')) @php(the_row())
    @if (get_row_layout() == 'title_and_content')

      @include('partials/content-element-title-and-text')

    @elseif (get_row_layout() == 'dividing_line')

      @include('partials/content-element-dividing-line')

    @endif
    <?php $row++; ?>
  @endwhile
@else
  // no layouts found
@endif
```

That way I can call the correct value:  
`{{ $title_text_background_color[$row] }}`

---

## Post 52 by @PunchRockgroin — 2017-02-14T22:28:49Z

Is there a way to use this same filter to add data to a custom post type partial in an archive loop… i.e. if the partial is ‘content-tc\_events.blade.php’, adding additional content to the $data array? I see how it uses the body\_classes to add the filter names dynamically.

My use case is to do some height/width calculations on the featured image to determine positioning.

---

## Post 53 by @inthedeepend — 2017-02-15T22:36:08Z

Curious how people are creating controllers. Assuming we follow best practice of attaching controllers to the appropriate views only. This is how the filter should be constructed for the home page, alas it works.

```
add_filter('sage/template/home/data', function ( $data, $template ) {
```

However away from the home page - I am having trouble getting my controllers attached to my views e.g

```
add_filter('sage/template/testimonials/data', function ( $data, $template ) {
```

Any and all help very much appreciated.  
Thanks

---

## Post 54 by @MWDelaney — 2017-02-16T00:12:58Z

Can someone with a stronger understanding of how PHP works explain why the above anonymous function method is preferable to a named function? The fact of the filter makes it so the function won’t be running on pages it isn’t called on. Is it so that the function CAN’T be called on inappropriate pages?

---

## Post 55 by @swalkinshaw — 2017-02-16T05:01:53Z

It’s just shorter/easier, not much else to it /shrug

---

## Post 56 by @stefanlindberg — 2017-02-16T17:21:34Z

I find this thread great. Everything I need to get started with Blade templates which I havn’t used before. Really enjoy this new way of writing templates.

One small/stupid question. Is there a way to enable Blade to parse `;` as PHP?

I have the habit of writing `@endif` as `@endif;` which outputs `;` which sometimes takes time to notice and are difficult to find later.

Not a big issue but anyway thought I’d ask :slight_smile:

Keep up the great work! And I’d be happy to help with documenting these best practises when Sage is out of beta.

---

## Post 57 by @kaisermann — 2017-02-17T02:47:05Z

I’m doing a wrapper for the add\_filter method:

[https://github.com/kaisermann/selene/blob/master/src/controllers.php](https://github.com/kaisermann/selene/blob/master/src/controllers.php)  
[https://github.com/kaisermann/selene/blob/master/src/controllers/global.php](https://github.com/kaisermann/selene/blob/master/src/controllers/global.php)

And the `includeArrayOfFiles` is in a modified functions.php:  
[https://github.com/kaisermann/selene/blob/master/functions.php#L43](https://github.com/kaisermann/selene/blob/master/functions.php#L43)

---

## Post 58 by @withjacoby — 2017-02-17T12:02:25Z

I’ve been following this discussion closely and had some time to create a controller mu-plugin which implements ideas mentioned in this thread.

It’s a work in progress, so may require some more testing, but I’ve put the beta release up, [https://github.com/soberwp/controller](https://github.com/soberwp/controller).

The plugin allows you to create controllers using the same standard WordPress template hierarchy that we’re used to. Your controller files sit in a src/controllers, or you can change the path based on a filter.

It also allows the use of components using standard PHP traits which can be included in each template controller.

**Here’s an quick basic usage example;**

```
<?php

namespace App;

use Sober\Controller\Controller;

class Single extends Controller
{
   // Importing a partial/component
   use Books;

    public function images()
    {
         return get_field('images')
    }
}
```

Protected and private methods don’t get exposed to the blade template, so you can use internal methods to do calculations/formatting, etc.

You can create a src/controllers/base.php for global vars.

---

## Post 59 by @MWDelaney — 2017-02-17T13:14:31Z

I like this a lot. It enforces structure that would be easy to half-ass if you’re working fast.

The only thing is that it makes it difficult to use the same controller on two filters if you ever need to. For instance I call the same thumbnail parameters on two templates and would prefer not to write the same function twice for that.

Still, I’m going to adopt this method going forward. I really dig it.

---

## Post 60 by @kaisermann — 2017-02-17T13:31:56Z

Oh, I agree with you! I think sharing the controller can be done with something like this:

```
function registerController( $scopes, $fn ) {
	if ( ! is_array( $scopes ) ) {
		$scopes = [$scopes];
	}
	foreach ( $scopes as $scope ) {
		add_filter( "sage/template/{$scope}/data", $fn, 10, 2 );
	}
}
```

Then, you could do `registerController(['template1','template2'], function...);`.

I’m also thinking about If I should declare the controllers in an array or if I should look for all files on the controllers directory instead…

---

## Post 61 by @MWDelaney — 2017-02-17T13:54:18Z

> [@kaisermann](#):
>
> I’m also thinking about If I should declare the controllers in an array or if I should look for all files on the controllers directory instead…

I was thinking about that, too. The “Roots way” as shown in `functions.php` would appear to be an array. So for consistency that makes sense.

---

## Post 62 by @christianmagill — 2017-02-18T18:19:54Z

Does anyone know if it’s possible to extract an array in Blade templates?

In PHP 7, I might do something like this to break apart an array in an encapsulated way:

```
(function($user){
   extract($user);
   echo "<p>$first_name $last_name</p>";
   ...
})();
```

I see Blade offers subviews, which may be useful in some contexts, but for others it may prove overkill.

---

## Post 63 by @stefanlindberg — 2017-02-20T09:21:41Z

It is possible to use extract in Blade templates. I just do this

```
@if ($postData)
  @php(extract($postData))
@endif
```

Might be better ways but this works

---

## Post 64 by @darjanpanic — 2017-02-20T12:27:11Z

Anyone tried the @yield and @extends blade functions? Can they be used with sage 9?

---

## Post 65 by @kalenjohnson — 2017-02-20T16:03:01Z

Not sure why they wouldn’t work. Each of the templates already uses `@extends`: [https://github.com/roots/sage/blob/master/templates/single.blade.php#L1](https://github.com/roots/sage/blob/master/templates/single.blade.php#L1)

`@extends` basically replaces the theme wrapper.

---

## Post 66 by @inthedeepend — 2017-02-21T06:06:28Z

This is brilliant. Thank you for your work.

---

## Post 67 by @christianmagill — 2017-02-21T18:43:12Z

Maybe by default make it pull all files from controllers directory, but allow for the data to be filtered.

---

## Post 68 by @christianmagill — 2017-02-22T15:59:06Z

Another option would be to provide a separate method for pulling an array of all the files in the controllers directory which one could use to populate the controllers array. Makes it a little more clear what’s happening.

---

## Post 69 by @aaroneight — 2017-02-22T16:53:29Z

With the soberwp/controller plugin, I’m wondering if it would be a wise setup to have controllers for specific components of a fairly complex page. So break up the page into partials, and then create a controller for each specific partial. On the main blade template I would then include all of the partials. How is everyone else breaking up large, complex pages with their controllers and templates?

---

## Post 70 by @swalkinshaw — 2017-02-22T17:38:26Z

“Controllers” usually corresponds to a single page/route, not per partial.

---

## Post 71 by @Log1x — 2017-02-23T04:22:00Z

I’m surprised nobody pointed it out sooner but Laravel 5.4 was released at the end of January and Blade got a new [feature](https://laravel.com/docs/5.4/blade#components-and-slots).

I posted an [issue](https://github.com/roots/sage/issues/1841) on the Sage tracker to get this updated for everyone, but manually bumping the version of both `illuminate` packages in `composer.json` to `~5.4.0` and running `composer update` worked fine for me after clearing Blade’s cache.

Components seem really nice and should help a good bit with organization in complex themes. They also accept data through an `array` or using the new `@slot` directive.

I can see a great use for this with things such as sliders, alerts, forms, various widgets, etc. used throughout the theme as well as breaking down complex partials into a component-based partial making it easier to maintain.

I went the route of creating a components folder inside of templates.

A generic use-case (which is also the example given on the Blade docs) would be alerts.

**Example**

_/templates/components/alert.blade.php_

```
<div class="alert alert-warning">
  {{ $slot }}
</div>
```

_/templates/partials/example.blade.php_

```
@component('components.alert')
  {{ __('Sorry, no results were found.', 'sage') }}
@endcomponent
```

This can be made more complex using the `@slot` directive or by passing an array of data to `@component`.

**Example 2**

_/templates/components/alert.blade.php_

```
<div class="alert alert-warning">
  <div class="alert-title">{{ $title }}</div>
  
  {{ $slot }}
</div>
```

_/templates/partials/example.blade.php_

```
@component('components.alert', ['title' => 'Warning'])
  {{ __('Sorry, no results were found.', 'sage') }}
@endcomponent
```

---

## Post 72 by @chrissi — 2017-02-23T08:51:22Z

I’m not sure if this is the right place to ask this, so let me know if this is improper and I’ll make a new topic.

I recently found out that, in Sage 9, Blade is setup to compile templates to PHP files and write them to the media uploads folder. If the file changes, Blade will recompile the file and write the update to the cache. If the file has not changed, and it already exists, it will be loaded from the cache.

I think that’s great that it has a cache. It saves CPU and makes sense.

However, I’m wondering if there’s a way to precompile the cache when I deploy to the server, rather than the default behaviour of checking upon page request.

I found this out because I’m using a plugin to offload the media uploads to s3, and it caused pages to stop loading (white screen of death). The blade cache was being offloaded to s3, and then could not be loaded because `allow_url_include` is (and definitely should be!) disabled, so PHP from remote servers cannot be executed. So I had to change the directory where Blade stores its compiled templates to ensure it’s stored and loaded locally. (For me, the config to change it was at /src/setup.php:127, changing `view.compiled` to `WP_CONTENT_DIR . "/uploads/cache/compiled"` instead of `"{$paths['dir.upload']}/cache/compiled"`).

It would make a lot more sense to be able to precompile the templates. They aren’t going to change between deploys, and then I can set my file system to truly be read-only and harden it up.

Is there a way to force Blade to precompile the files upon deploy and stop the compile-on-request behaviour? I tried looking at Laravel’s docs and searching the web and couldn’t find anything about this.

---

## Post 73 by @withjacoby — 2017-02-28T18:22:11Z

I reworked the plugin a bit since the alpha, not sure if you’re tracking, but it now works on page/route.

I’ve made it implement the same hierarchy as WordPress templates so you don’t have to duplicate controllers if for example `single.blade.php` and `page.blade.php` have the same data. You could just use `src/controllers/singular.php` to pass to both. It also enables you to inherit data from the controller hierarchy (if you want, it overrides by default) and you can use `src/controllers/base.php` for global vars.

You can include partials/components data by using standard PHP traits. You can view the docs on the github [readme](https://github.com/soberwp/controller/blob/master/README.md) which explains it better, but it makes it easier to reason about.

---

## Post 74 by @swalkinshaw — 2017-02-28T21:48:46Z

That’s a really good question.

I found a [compile](https://laravel.com/api/5.4/Illuminate/View/Compilers/BladeCompiler.html#method_compile) method. Maybe we can write a Composer script to precompile all templates.

edit: I opened an issue: [https://github.com/roots/sage/issues/1851](https://github.com/roots/sage/issues/1851)

---

## Post 75 by @chrissi — 2017-03-01T06:03:50Z

Thanks @swalkinshaw. It would make me so happy to have this feature! :thumbsup:

---

## Post 76 by @alwaysblank — 2017-03-01T17:33:12Z

I wrote a very simple WP CLI package to do this: [https://github.com/alwaysblank/blade-generate](https://github.com/alwaysblank/blade-generate) There are probably a ton of ways to improve on it, but in the short term anyone should be able to hook this into a deploy script and get the desired effect.

---

## Post 77 by @stefanlindberg — 2017-03-02T13:56:14Z

@withjacoby your controller plugin looks awesome and I want to try it.

Two stupid questions… I can’t install it following the instructions `composer require soberwp/controller`. Not found. Do I need to add the repository to composer somehow?

I’m my custom controller in my project I run `add_action('the_post', function ($post_object) { ... });`

This is not optimal because it runs multiple times per page load but it was easiest for me while learning blade… How would a similar controller look using the plugin. What I’m trying to achieve is fetching data for different post types not just at single pages but also when in custom loops.

Thanks!

---

## Post 78 by @kaisermann — 2017-03-02T14:17:28Z

Is there a way to load the plugin without it being a WordPress plugin? I mean, is it possible to autoload it just like sage’s `src/lib/Sage`?

---

## Post 79 by @withjacoby — 2017-03-02T14:48:14Z

**EDIT:** You can now use `composer require soberwp/controller:dev-master`

I’m not sure I understand your use case, but I would create a custom controller for the archive pages. So you would have `src/controllers/archive-{post_type}.php` and pass the data through that. If you wanted to pass to the post type archive page and single page you could create a component and include in each controller.

I’m not sure that answers your question?

---

## Post 80 by @withjacoby — 2017-03-02T14:55:29Z

This seems to be working for me, but haven’t done much testing so let me know if it throws an error, if so, you can create a github issue.

Place all the plugin files in `src/lib/Sober/Controller/`

Include somewhere in functions.php

`include_once get_stylesheet_directory() . '/src/lib/Sober/Controller/controller.php';`

---

## Post 81 by @aaroneight — 2017-03-02T16:49:26Z

Have you also ensured that your composer minimum-stability is set to beta?

---

## Post 82 by @christianmagill — 2017-03-07T15:18:06Z

Any ideas how to implement the @optional directive from your Laracast link?

It references the yieldContent method.

---

## Post 83 by @mephilip — 2017-03-15T20:34:01Z

how would you reference the post1 function inside of the post2 function?

---

## Post 84 by @mephilip — 2017-03-15T20:34:49Z

How would you reference one function inside of another function using this syntax?

---

## Post 85 by @JulienMelissas — 2017-03-25T17:02:11Z

I’ve been enjoying my `@shortcode` directive for blade, as simple as it is…

```
/**
 * Create @shortcode() Blade directive
 */
sage('blade')->compiler()->directive('shortcode', function ($shortcode) {
    return '<?= do_shortcode(\''. $shortcode .'\'); ?>';
});
```

---

## Post 86 by @smutek — 2017-03-25T19:24:47Z

> [@mephilip](#):
>
> How would you reference one function inside of another function using this syntax?

Hey, sorry, I’ve been wrapped up with work stuff. How about -

```
// fruit stand entrepreneur
function name($name)
{
    return $name . '\'s Fruit World.';
}
// fruits for sale
function fruits()
{
    $fruits = ['apple', 'orange', 'pineapple'];
    return $fruits;
}
// use on a page called Fruit Stand (ie. body class fruit-stand)
add_filter('sage/template/fruit-stand/data', function () {

    $data['name'] = name('Bob'); // name function - string
    $data['fruits'] = fruits(); // fruits function - array
    return $data; // return data
});
```

Template -

```
<h2>{{ $name or 'Name not defined' }}</h2>

<h3>Fruits for Sale</h3>
<ul>
  @forelse( $fruits as $fruit )
  <li>{{ $fruit }}</li>
  @empty
  <li class="alert alert-danger">No Fruits!</li>
  @endforelse
</ul>
```

What are you trying and what sorts of problems are you running into?

---

## Post 88 by @intelligence — 2017-04-03T06:27:35Z

Curious, how would I setup a custom loop utilizing the controller? My use case is that for single posts I also want to fetch all other posts to show in a list on the same page.

This is what I’m trying

Controller:

```
use WP_Query;
use Sober\Controller\Controller;

class Single extends Controller {
    /**
     * Return all People posts
     *
     * @return array
     */
    public function people() {
      $people = new WP_Query( ['post_type' => 'people'] );
      return $people;
    }
}
```

View:

```
@while($people->have_posts()) @php(the_post())
    test
@endwhile
```

Which results in  
`Xdebug: Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function have_posts() on null in`

---

## Post 89 by @withjacoby — 2017-04-03T10:29:10Z

@intelligence been able to get it working on my side, try the following

```
@while($people->have_posts()) @php($people->the_post())
    {{ the_title() }}
@endwhile
```

If it’s still not working, you can use @debug or @debug(‘dump’) within the Blade directive to see if it’s returning $people correctly.

---

## Post 90 by @intelligence — 2017-04-03T10:58:12Z

Well that did it, thank you!

---

## Post 91 by @smutek — 2017-04-04T17:33:33Z

> [@withjacoby](#):
>
> It’s a work in progress, so may require some more testing, but I’ve put the beta release up, [GitHub - soberwp/controller: Composer package to enable a controller when using Blade with Sage 9](https://github.com/soberwp/controller).

Man, this is so nice. Kudos @withjacoby!

---

## Post 92 by @anon21078981 — 2017-04-17T14:19:15Z

@withjacoby Hi! I’m struggling with getting `controller` to work, wondering if you could help me out.

I’m running

- Sage 9.0.0-beta2
- Controller 9.0.0-beta2.1 installed and activated as a MU plugin

In `./src/controllers/single.php` I have the following:

```
<?php

namespace App;

use Sober\Controller\Controller;

class Single extends Controller
{
    public function hello()
    {
        return "hello";
    }
}
```

Calling `{{$hello}}` in `./resources/views/single.blade.php` returns:

```
Undefined variable: hello
```

I ran debugging and get the following:

```
// @debug('hierarchy')

Hierarchy Debugger:
- /src/controllers/base.php
- /src/controllers/singular.php
- /src/controllers/single.php
- /src/controllers/single-episode.php
```

```
// @debug('controller')

Controller Debugger:
```

```
// @debug('dump')

. /current/web/app/mu-plugins/controller/src/Module/Debugger.php:55:
array (size=0)
  empty
```

---

## Post 94 by @withjacoby — 2017-04-17T14:33:49Z

@anon21078981 just want to make sure before setting up my side, is this a typo?

`./resources/views/single.base.php`

If not, try rename to `single.php` and let me know?

Also, just noticed, `./resources/view/` is for dev-master. For 9.0.0-beta.2, it should be `./templates/single.blade.php`

---

## Post 95 by @anon21078981 — 2017-04-17T14:38:31Z

@withjacoby Thanks for the quick response. Indeed, I meant to say `./resources/views/single.blade.php`.

Renaming it to `single.php` breaks Sage.

That’s strange, `package.json` reads `"version": "9.0.0-beta.2"`.

Perhaps I’ll try reinstalling Sage.

---

## Post 96 by @withjacoby — 2017-04-17T14:43:01Z

Sorry, yes `./resources/views/single.blade.php` is correct.

I think try reinstalling and let me know if that helps, it’s likely not finding the Controller files if the path filter is incorrect, which is different between dev-master and 9.0.0-beta.2 so that may be the problem.

---

## Post 97 by @anon21078981 — 2017-04-17T15:00:44Z

I just re-ran `composer create-project roots/sage your-theme-name dev-master` and `package.json` still reads `"version": "9.0.0-beta.2"`.

My views are still in `./resources/views/`. Do you know if this is normal?

---

## Post 98 by @withjacoby — 2017-04-17T15:05:19Z

That doesn’t sound correct.

But you do have the dev-master version, so you could try the dev-master version of Controller which will work with your version.

---

## Post 99 by @anon21078981 — 2017-04-17T15:33:44Z

I reinstalled `dev-master` versions of both Sage and Controller and I’m still having the same issue.

Do you have any tips on how I should debug?

---

## Post 100 by @withjacoby — 2017-04-17T15:35:21Z

@anon21078981 any chance you can upload your theme folder to github and I’ll take a look?

You can DM me your email so we don’t flood this thread.

---

## Post 101 by @MWDelaney — 2017-04-17T20:17:54Z

Hey, I was getting undefined variables in my `Base` controller, too. I’m using `dev-master` for both `Controller` and `Sage`.

Turns out `base.blade.php` was renamed to `app.blade.php` recently. Renaming my controller fixed the issue.

---

## Post 102 by @withjacoby — 2017-04-17T20:31:46Z

That’s correct. dev-master is on par with Sage dev-master, so using `resources/controllers/App.php` is the correct usage.

I’ve updated the docs to reflect this.

---

## Post 103 by @mladimatija — 2017-04-18T18:16:00Z

Hello there :slight_smile: I’ve started using Sage few weeks back locally, on my development setup where everything works fine, but when I try to deploy on my shared hosting server I get the following error:

```
: Uncaught ReflectionException: Class Illuminate\Filesystem\Filesystem does not exist in /home/user/domain.com/wp-content/themes/test/vendor/illuminate/container/Container.php:719
Stack trace:
#0 /home/user/domain.com/wp-content/themes/test/vendor/illuminate/container/Container.php(719): ReflectionClass->__construct('Illuminate\\File...')
#1 /home/user/domain.com/wp-content/themes/test/vendor/illuminate/container/Container.php(598): Illuminate\Container\Container->build('Illuminate\\File...')
#2 /home/user/domain.com/wp-content/themes/test/vendor/illuminate/container/Container.php(567): Illuminate\Container\Container->resolve('Illuminate\\File...')
#3 /home/user/domain.com/wp-content/themes/test/vendor/illuminate/container/Container.php(246): Illuminate\Container\Container->make('Illuminate\\File...', Array)
#4 /home/user/domain.com/wp-content/themes/test/vendor/illuminate/container/Container.php(716): Illuminate\Container\Container->Illuminate\Contain in 

on line 719
```

I’ve followed the steps outlined in Sage Docs, installed Composer on the server, run the “composer install” command from theme directory but I still get this error. I’ve tried with my custom theme and clean theme directly from master branch on GitHub repo.

I’ve tried with PHP versions 5.6 and 7.0.

Any help would be greatly appreciated as I’m stuck on this for more than a day now :slight_smile:

---

## Post 104 by @intelligence — 2017-04-19T18:57:01Z

I’m curious, why involve the controller at all for this example? Seems like it makes it complex, what am I missing? :slight_smile:

---

## Post 105 by @strarsis — 2017-05-13T18:02:29Z

How to can a PHP function used in blade?  
I defined a custom one in helpers.php - but blade cannot find it.  
Do I have to add the helpers.php to composer.json as described in

> <https://stackoverflow.com/questions/28290332/best-practices-for-custom-helpers-on-laravel-5/28290359#28290359>

---

## Post 106 by @ben — 2017-05-13T20:50:20Z

Without knowing exactly what you’re doing (code examples), it’s hard to help.

There is nothing special about using PHP functions in Blade.

---

## Post 107 by @julykaz — 2017-05-17T20:31:40Z

I guess it should be enough to call your method in blade template this way - App\method()

---

## Post 108 by @strarsis — 2017-05-17T21:39:00Z

Thanks for all the answers. I got it working by adding a new php file with these helpers to composer.json as described in

> <https://stackoverflow.com/questions/28290332/best-practices-for-custom-helpers-on-laravel-5/28290359#28290359>

---

## Post 109 by @alwaysblank — 2017-05-22T22:57:16Z

I recently updated my WP-CLI template compiler plugin to be (marginally) more flexible and powerful:

- Finds all `.blade.php` files and compiles them (no more hard-coding template directories)
- Accepts a `directory` argument to limit it to a specific theme subdirectory

> **[alwaysblank/blade-generate](https://github.com/alwaysblank/blade-generate)**
>
> blade-generate - Forces generation of Blade template cache files for Sage9.

---

## Post 110 by @intelligence — 2017-05-31T07:04:32Z

Would be a bit interesting to see how you guys setup your views. I’m curious how you tackle ACF fields such as a repeater field. I saw there was an example earlier in the thread where `have_rows` is used in the view.

I’ve been going back and forth with using `have_rows`in the view, and setting up the controller to loop all data into an array which then is output in the view. This way I lose the ACF logic from the view, which to me feels a bit cleaner, but also a little bit more work.

How do you do it?

---

## Post 111 by @joneslloyd — 2017-05-31T12:26:05Z

Hey @withjacoby - Really great plugin, cheers!

I’m using it by putting the plugin contents in `/app/lib/Sober/Controller/`, and then in `functions.php` adding `'lib/Sober/Controller/controller'` to the `array_map` function (if anybody cares).

I’m including Controller like [this](https://twitter.com/withjacoby/status/869611219543576576)

I see @vdrnn’s solution [above](https://discourse.roots.io/t/best-practice-resources-for-blade/8341/51?u=joneslloyd), but is there not a nicer way to handle ACF’s repeater field, so that `get_row_layout()` can be called in a `while` loop to get a partial for that particular layout?

For example, I have:

```
@if(have_rows($item_header))
	<div class="page-header">
    @while(have_rows($item_header))
			<div class="{{('full-width' === $item_header_layout) ? 'container-fluid' : 'container'}}">
				<div class="row">
					<div class="page-header-inner {{$item_header_layout}}">
						@php(the_row())
						@php(get_template_part('views/flexibles/' . get_row_layout()))
					</div>
				</div>
			</div>
    @endwhile
	</div>
@endif
```

But I’ve discovered that `the_row()` and `get_row_layout()` (or indeed the while loop) won’t work by using the Controller to put `get_field` into the `$item_header` variable…

I tried a variation of the code available [here](https://github.com/soberwp/controller/issues/11#issuecomment-291278258), but this won’t allow me to utilise a particular template partial depending on the ACF field in question.

Any pointers on this would be a huge help!

**EDIT:**  
For now, I’ve decided to not use ACF Repeater / Flexible Content fields with Controller, else I’m looping twice (one in the Controller, then once on the page) – I’m just using it instead for simple variables.

Great work though! Thanks again :slight_smile:

---

## Post 112 by @withjacoby — 2017-05-31T19:38:48Z

Hey @joneslloyd,

Thanks so much.

I agree with the way you’re doing it now, I do it the same way.

In some cases, if there aren’t that many fields I will do the acf loop within Controller and expose an array to loop through. But I think if there are lots of fields then use the acf loop within the view. You can get data within the acf loop using a public static method which also may be useful in some cases, [https://github.com/soberwp/controller#using-static-methods](https://github.com/soberwp/controller#using-static-methods)

---

## Post 113 by @joneslloyd — 2017-06-01T07:59:46Z

Thanks for the clarification.

I’l check out using static methods as a way of dealing with ACF data.

Cheers

---

## Post 114 by @withjacoby — 2017-06-03T10:44:48Z

Hi all,

For those using [Controller](https://github.com/soberwp/controller), please note that it is now a Sage dependency.

You can remove the mu-plugin and run `composer require soberwp/controller:9.0.0-beta.3` from within the theme directory.

That’s all that’s needed.

---

## Post 115 by @patrickv — 2017-06-03T15:16:42Z

Is it possible you would need to remove composer’s type “wordpress-muplugin”. Despite having run composer clear-cache, It installs in [sage]/wp-content/mu-plugins/… folder instead of vendor/soberwp/controller.

> <https://github.com/soberwp/controller/blob/master/composer.json#L3>

---

## Post 116 by @withjacoby — 2017-06-03T21:34:58Z

So sorry! that’s such an oversight, should be fixed now.

---

## Post 117 by @intelligence — 2017-08-23T07:33:40Z

Can you please show an example how you use/not use sober? I’m usually using repeaters and flexible content alot, and it feels very weird and unefficient to loop over these fields in the controller, and then do the same in the view again.

Great tool none the less, thanks! :slight_smile:

---

## Post 118 by @withjacoby — 2017-08-23T08:39:53Z

@intelligence for the most part, I still use the Advanced Custom Fields functions within the views, esp if within a loop. I will use Controller if I need to write some logic into the returned results though.

There are some good examples here though, esp the object syntax being used by @nathobson

> [@ACF variables in blade template](https://discourse.roots.io/t/acf-variables-in-blade-template/10180/5):
>
> In your second example, you’d be able to access video in your Blade with the following: {{$homepage\_fields['video']}} Methods in the App namespace are available to every Blade, unless they’re overwritten by another controller–i.e. if you had a controllers/FrontPage.php controller file that also defined homepageFields(), the $homepage\_fields variable in views/front-page.blade.php would contain the value returned by the controllers/FrontPage.php version of homepageFields() instead of the one def…

I’ll see if I can write up some use-cases/examples down the line. I have been wanting to create nicer documentation with an easier way to consume, so will work on that.

**EDIT:** I may look at doing a Sober/Controller/Acf helper class. Could be useful and speed up templating when using acf a lot.

---

## Post 119 by @ksr583 — 2017-08-24T20:56:29Z

That would be awesome. I’m trying to do this right now and struggling a bit.

---

## Post 120 by @Twansparant — 2017-08-25T13:03:02Z

I was wundering if it’s possible to use a **Trait** used in the Sober controllers in a normal non-blade php file?

Let’s say I have a controller **TemplateCustom.php** where I want to use **TraitA** :

```
namespace App;
use Sober\Controller\Controller;

class TemplateCustom extends Controller {
	use TraitA;

	public function controlFields() {
		return (object) array (
			'posts' => TraitA::getPosts()
		);
	}
}
```

In my **TraitA** :

```
namespace App;

trait TraitA {

	/* Get all Posts */
	public static function getPosts() {
		$postsObj = [];
		$posts = get_posts([
			'post_type' => 'post-type',
			'orderby' => 'title',
			'order' => 'ASC',
			'posts_per_page' => -1
		]);

		foreach ($posts as $post) {
			$postsObj[] = self::getPost($post->ID);
		}

		return json_decode(json_encode($postsObj));
	}

	/* Get Single Post */
	public static function getPost($id = null) {
		if ($id) {
			$post = get_post($id);
			$data = [
				'title' => get_the_title($id),
				'link' => get_the_permalink($id),
				'slug' => $post->post_name
			];

			return json_decode(json_encode($data));
		}
	}
}
```

and a blade view **template-custom.blade.php** where I use the returned Trait data:

```
{{--
  Template Name: Custom Template
--}}

@extends('layouts.app')

@section('content')
	@while(have_posts()) @php(the_post())
		@include('partials.content-post', array(
			'posts' => $control_fields->posts
		))
	@endwhile
@endsection
```

This works great!  
However, I think these traits are only available within the Sober Controllers?

What if I want to re-use the **TraitA** functions in a normal php class outside the blade controllers & views:

```
class TraitTest {
	use TraitA;

	public function __construct() {
		add_filter('some_filter', 'populatePosts', 10, 2);
	}

	function populatePosts() {
		$posts = TraitA::getPosts();
		return $posts;
	}
}

new TraitTest;
```

The above will result in an error:

```
Fatal error: Trait 'TraitA' not found
```

Is my Trait approach wrong here?

Any help is welcome, thanks!

---

## Post 121 by @withjacoby — 2017-08-25T13:18:33Z

Can’t fully test right now, but my first feeling would be that the Trait is only included from Controller after your custom class is included.

---

## Post 122 by @kalenjohnson — 2017-08-25T15:40:39Z

> [@Twansparant](#):
>
> Fatal error: Trait ‘TraitA’ not found

My guess is because you didn’t import it and you’re not using the correct namespace. From the code you posted, it’s not `TraitA`, it’s `App\TraitA`

---

## Post 123 by @Twansparant — 2017-08-26T11:17:34Z

> [@kalenjohnson](#):
>
> From the code you posted, it’s not TraitA, it’s App\TraitA

Thanks for your reply!  
You mean in the Trait import line:

```
use App\TraitA
```

or in the function call:

```
App\TraitA::getPosts();
```

Because both don’t work…

Do I need to declare the `namespace App`; in my php file too?  
In both cases I still get the same error unfortunately:

```
Fatal error: Trait 'TraitA' not found
```

Am I doing something wrong?

---

## Post 124 by @alwaysblank — 2017-08-26T15:30:08Z

Like @withjacoby said, your Trait probably hasn’t been loaded by the time you’re trying to call it–Controller loads the Classes and Traits for your data itself, they’re not autoloaded like most other classes in Sage.

If you have a Trait that you want to use in your controller and elsewhere, I’d probably do that by creating my Trait outside of the Controller ecosystem, and either load the file containing it manually (i.e. w/ `functions.php`) or set it up to use Composer’s autoloading. That way you can easily access it anywhere you want.

---

## Post 125 by @kalenjohnson — 2017-08-28T18:22:55Z

Maybe everyone else is on to something. Where did you place the `TraitA` file?

---

## Post 126 by @Twansparant — 2017-08-28T18:36:14Z

In the _app/controllers/partials_ folder

---

## Post 127 by @kalenjohnson — 2017-08-28T18:49:51Z

That’s probably the issue… PHP doesn’t know where to find the class because you’re not following the autoloading conventions.

Sage is autoloaded with PSR-4: [https://github.com/roots/sage/blob/681ad997a2d56ddc2a7fad135ab03e21ff56f565/composer.json#L29-L33](https://github.com/roots/sage/blob/681ad997a2d56ddc2a7fad135ab03e21ff56f565/composer.json#L29-L33)

I would put that class in `app/Traits`, with the namespace `App\Traits`, and load it in other files `use App\Traits\TraitA`, which should get it autoloaded correctly. Just remember, PSR-4 basically means having your namespaces follow your folder structure.

---

## Post 128 by @MWDelaney — 2017-08-28T19:12:43Z

Doesn’t Controller suggest the use of the `partials` directory, though?

---

## Post 129 by @kalenjohnson — 2017-08-28T19:26:17Z

Yes, apparently SoberWP does… I’ll have to take a closer look…

---

## Post 130 by @withjacoby — 2017-08-28T19:41:13Z

Controller doesn’t require the use of PSR4 loading, anything within the controllers/ directory is included, and it will determine traits from classes, and then load the traits first.

I’ll do some testing re using traits outside of Controller and see what I can come up with, but I’m fairly confident it has to do with the order.

---

## Post 131 by @kalenjohnson — 2017-08-28T19:48:35Z

Can I ask what the thought process is behind loading everything in the controllers folder and not following PSR-4? I apologize if this has been discussed previously, I’ve been busy the last couple months moving, haven’t been keeping up with Roots stuff, just starting to catch up now.

---

## Post 132 by @ned — 2017-08-28T19:50:28Z

Possible related: I’ve run into [an issue](https://discourse.roots.io/t/controller-doesnt-work-when-installing-sage-based-theme-via-composer/10272/10) where Controller’s classes aren’t loaded when a Sage-based theme is installed via Composer.

---

## Post 133 by @withjacoby — 2017-08-29T08:28:43Z

Controller uses some info from the includes for the loader, functions like get\_declared\_classes(). I am going to look into using PSR4 though, because if I could get it working it could reduce some code from class Loader.php, and as you mentioned, would help standardise it more to be in line with Sage.

---

## Post 134 by @Twansparant — 2017-08-31T09:59:20Z

Ok, when I manually load the Trait file like this:

```
array_map(function ($file) use ($sage_error) {
	$file = "../app/{$file}.php";
	if (!locate_template($file, true, true)) {
		$sage_error(sprintf(__('Error locating <code>%s</code> for inclusion.', 'sage'), $file), 'File not found');
	}
}, ['helpers', 'setup', 'filters', 'admin', 'controllers/partials/TraitA']);
```

I can use the Trait like this:

```
App\TraitA::getPosts();
```

without setting `use App\TraitA`

---

## Post 135 by @withjacoby — 2017-08-31T10:31:10Z

Cool, so it’s just a matter of the order it’s being loaded in, as I thought would be the case.

If we could get Controller to use PSR4 that should resolve. I will look into it this weekend.

---

## Post 136 by @withjacoby — 2017-09-01T17:11:49Z

Looks like PSR4 loading is possible with changes to the Loader.

Is everyone for using PSR4? It seems like it would be the correct approach, but would be good to hear feedback prior to implementing a ‘breaking’ change. (this will live in dev-master until a new tag/release is done)

You would need to make changes to your Controller files though.

- The namespace would change to **App\Controllers** and to **App\Controllers\Partials** (to match the folder names, as per PSR4 autoloading standards)
- For using traits within Controller files, you would need to specify the added namespace, or let them live in the same directory.

**app/controllers/About.php**

```
<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class About extends Controller
{
    use Partials\TraitName;
}
```

**app/controllers/partials/Testing.php**

```
<?php

namespace App\Controllers\Partials;

trait Testing
{
    public function example()
    {
        return 'Example';
    }
}
```

@Twansparant this should as a result solve the order issue as well, but not tested yet.

---

## Post 137 by @Log1x — 2017-09-05T00:59:24Z

I submitted a PR to bump `illuminate/support` to 5.5 which includes the new [`@switch`](https://laravel.com/docs/5.5/blade#switch-statements) statements and my personal favorite, [custom if statements](https://laravel.com/docs/5.5/blade#custom-if-statements).

The custom if statements work similar to the directives that I posted examples of above, but instead can simplify if statements dramatically.

A small example would be checking if an ACF field exists. Before, our directive would look somewhat like this:

```
$sage = sage('blade')->compiler();

/**
 * Create @hasField() Blade directive
 */
$sage->directive('hasField', function ($expression) {
    $expression = strtr($expression, ['(' => '', ')' => '']);
    return "<?php if (Acf::field($expression)->get()) : ?>";
});

/**
 * Create @endField Blade directive
 */
$sage->directive('endField', function () {
    return "<?php endif; ?>";
});
```

Not too bad, but a little dramatic to make two separate directives, and if you’re anything like me, to achieve a clean Blade syntax I was ending up with dozens of Blade directives that were simply an `endif`.

With the new Custom If Statements, that shouldn’t be such an issue anymore. To achieve the above, we simply do:

```
$sage = sage('blade')->compiler();

/**
 * Create @hasField() Blade directive
 */
$sage->if('hasField', function ($field) {
    return Acf::field($field)->get();
});
```

and this alone will automatically create an `@endHasField()` directive allowing you to quickly check if your field exists.

To clarify, `->if()` will always expect a `boolean`.

[note: above examples are using [acf-fluent](https://github.com/samrap/acf-fluent).]

**Edit:** `->if()` might have potential issues with Sage at the moment. [See here](https://github.com/roots/sage/pull/1962#issuecomment-327062485)

---

## Post 138 by @Webstractions — 2017-10-11T17:15:17Z

@Log1x have you found a workaround for `->if()` yet?

---

## Post 139 by @Webstractions — 2017-10-11T17:34:45Z

After reading and using a lot of what was discussed here, I thought there could be an easier way. I created an extension package named [Sage Xpress](https://github.com/webstractions/sage-xpress) which is available on GitHub.

There are Blade Directives for loop, query, menu, sidebar, etc. An optional `config/blade-directives.php` is available for you to easily extend with your own directives. [umm, wouldn’t let me put at-signs in front of the directives – thinks I am mentioning users – LOL]

A MenuProvider which is completely configurable via `config\menu.php` and using the `@menu('menuId')` in your blade file. The provider handles the registration and rendering of the menu. No controller file needed, no setup functions needed, easy-peasy.

I will be adding providers for Sidebar, Shortcodes, and whatever you guys can come up with and think would be handy.

Setup is easy. Composer require the package and add one line of code to your `setup.php`. You don’t have to register your menus there, so you can safely delete that action. Config files are automatically added to `sage()['config']` so no messing with `functions.php` either.

This package is supposed to copy the config stubs into your config directory if they don’t exist, but I have not fully tested this yet. It is my first composer package using scripts – crossing my fingers. If they do not get copied over, you can find them in the `vendor/webstractions/sage-xpress/config` directory.

EDIT: I have a problem with merging custom blade directives with the BladeDirectives provider right now. Working on it.

---

## Post 140 by @Webstractions — 2017-10-13T18:42:20Z

I just added Schema and Attribute support to [Sage Xpress](https://github.com/webstractions/sage-xpress). As an example, it allows you to do something like this for a single post

```
<article @schema('entry')>

      <header class="entry-header">
        @include('partials.entry.title')
        <div class="entry-meta entry-byline">
          <span @schema( 'entry-author' )>
            @php( the_author_posts_link() )
          </span>
          <span @schema( 'entry-published' )>
            <?= get_the_date(); ?>
          </time>
          </span>
          <a href="@php(comments_link())" class="comments-link post-comments">
            @php( comments_number( esc_html__( 'No comments','sage' ), esc_html__( 'One comment','sage' ), esc_html__( '% comments','sage' ) ) )
          </a>
        </div>
      </header>

      <div @schema('entry-content')>
        @php(the_content())
      </div>

    </article>
```

This provider will spit out `schema.org` markup and basic classes. It is based on Justin Tadlock’s `hybrid_attr()` function from Hybrid Core. He has removed the [schema.org](http://schema.org) portion from his later releases.

The classes that are injected are slightly opinionated, but are easily over-ridden with filters.

After looking at all of the ACF directives, I am working on a similar provider with just one directive `@acf('slug')` that will accomplish the same thing. If anyone would like to help, drop me a note.

---

## Post 141 by @robrecord — 2017-10-30T15:45:36Z

I’m using Sage 9 for the first time, and am confused about the About.php and Home.php controllers in sage/app/controllers/.

After reading the Sober documentation, I realised that Home.php would be used when the exact WordPress template was home.php. Neither front-page or page-home would suffice; I would need a controller called Front-page.php or Page-home.php for those templates.

Still, I am confused by the presence of About.php - which template will this be activated on, or is it simply supposed to be used statically?

Hope someone can shed some light!

---

## Post 142 by @robrecord — 2017-10-30T15:47:12Z

Also - should I name my Front-page.php controller as FrontPage, or something else?

---

## Post 143 by @ben — 2017-10-30T15:56:09Z

Regarding your last two replies:

> <https://github.com/roots/sage/pull/1986>

---

## Post 144 by @YarGnawh — 2017-10-30T16:20:18Z

I didn’t know about the new controller file structure until I did a composer update and everything broke. But after I moved all the controllers to app/controllers it still does not work. I get this error:

`Uncaught ReflectionException: Class App\\Controllers\\template-home does not exist in /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php`

Full error below

```
[Mon Oct 30 16:05:49.409392 2017] [:error] [pid 1366] [client 172.17.0.1:43296] PHP Fatal error: Uncaught ReflectionException: Class App\\Controllers\\template-home does not exist in /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php:19\nStack trace:\n#0 /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php(19): ReflectionClass->__construct('App\\\\Controllers...')\n#1 /app/wp/wp-includes/class-wp-hook.php(298): Sober\\Controller\\loader('')\n#2 /app/wp/wp-includes/class-wp-hook.php(323): WP_Hook->apply_filters(NULL, Array)\n#3 /app/wp/wp-includes/plugin.php(453): WP_Hook->do_action(Array)\n#4 /app/wp/wp-settings.php(448): do_action('init')\n#5 /app/wp-config.php(125): require_once('/app/wp/wp-sett...')\n#6 /app/wp/wp-load.php(42): require_once('/app/wp-config....')\n#7 /app/wp/wp-blog-header.php(13): require_once('/app/wp/wp-load...')\n#8 /app/index.php(4): require('/app/wp/wp-blog...')\n#9 {main}\n thrown in /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php on line 19, referer: http://localhost:3000/about-us/management-team/```
```

---

## Post 145 by @Webstractions — 2017-10-30T16:46:04Z

@YarGnawh If you did a direct copy of the controllers, make sure to check your `namespace` and `class` names.

Your file should be `app/controllers/template-home.php` with something along this in the file:

```
<?php
namespace App;

use Sober\Controller\Controller;

class TemplateHome extends Controller
{
    //
}
```

---

## Post 146 by @YarGnawh — 2017-10-30T16:54:54Z

hey @Webstractions, thanks for the help. That’s exactly what I have

```
<?php

namespace App;

use Sober\Controller\Controller;

class TemplateHome extends Controller
{
	public function heroCarousel()
    {
        return get_field('hero_carousel');
    }
}
```

One thing I did find out is that, in my composer.json `soberwp/controller` was using `dev-master`. After changing it to `~9.0.0-beta.4` , everything started working again. So I guess it’s something in the changes after beta4 that is breaking it.

```
"require": {
    "php": ">=7",
    "composer/installers": "~1.0",
    "illuminate/support": "~5.4",
    "roots/sage-lib": "~9.0.0-beta.4",
    "soberwp/controller": "~9.0.0-beta.4"
  },
```

---

## Post 147 by @Webstractions — 2017-10-30T16:58:46Z

Yeppers. I forgot about that little nugget. Glad you found it.

---

## Post 148 by @YarGnawh — 2017-10-30T17:00:09Z

I spoke too soon. There seems to be a new issue,

It appears that

`<html @php(language_attributes())>`

and many other `@php()` directives (not all) no longer works. When looking in the compiled files in cache, it outputs `<?php` without closing `?>`

At the moment, the only solution I found is replacing `@php()` with `@php .... @endphp`.

I’m not sure if this is a bug or an update. If it’s an update, the composer create-project will need an update.

> <https://github.com/laravel/framework/issues/20994>

---

## Post 149 by @Webstractions — 2017-10-30T18:22:37Z

Weird. `<html @php(language_attributes())>` works for me.

That appears to be a ~5.5 issue. Sage is currently using ~5.4

I, and some others, have upped our composer.json requirement to 5.5 and have had no ill effects except for using the new `if()` method for creating blade directives. One additional thing I did is I have my own fork of `sage-lib` which is also using 5.5.

Just dawned on me, you don’t need to use the `@php` directive for functions. You can do this as well:

```
<html {{ language_attributes() }}>
```

and for functions that return a string that you want to echo

```
<span>{{{ get_the_date() }}}</span>
```

In the latter case, muscle memory usually prevails and I just `<?= get_the_date(); ?>` without even thinking about it.

---

## Post 150 by @Simeon — 2017-11-27T00:55:54Z

> [@smutek](#):
>
> function slider( $data ) {
> 
> ```
> $images = get_field('images');
> ```
> 
> if ( $images ) {  
> $data[‘images’] = $images;  
> }
> 
> return $data;  
> }  
> add\_filter( ‘sage/template/home/data’, ‘App\slider’ );

Can you explain what’s being done with ACF Gallery here that couldn’t just be done with…

```
function logo_gallery()
  {
    $logo_gallery = get_field('logo_gallery');

    return $logo_gallery;
  }
```

---

## Post 151 by @smutek — 2017-11-27T02:04:26Z

Hi there. The filter makes the results available to the blade template via that `$data` variable. That was the way to do it back when I made that post.

I’m pretty sure it predates the Controller plugin, so keep in mind that things have changed a bit and I’m not fully up to speed.

That said, the function is just filtering the `$data` variable, which is a global variable available to templates.

So it:

- Takes `$data` as it’s input,
- Checks to see if there’s images available and,
  - if yes, adds them to the `$data` variable with the key `images` so, `$data['images']`).

- Returns the filtered `$data` variable to the script.

Meanwhile, back at the template, the contents of the variable `$images` is now available to the template, via `$data`.

Does that make sense?

---

## Post 152 by @Simeon — 2017-11-27T02:09:39Z

Oh right. So your original method was adding the ACF Gallery to an existing variable, where my method is just creating a new variable to store the same information?

I couldn’t get yours working because of ‘unexpected add\_filter’ errors, so perhaps things have changed with the introduction of the controller…

---

## Post 153 by @smutek — 2017-11-27T02:32:38Z

Exactly! If I remember correctly it’s now handled by the Controller, so no need for the filter.

Did you get it sorted? Looking at the Controller docs it’d be something like:

```
<?php

namespace App;

use Sober\Controller\Controller;

class Single extends Controller
{
    public function logo_gallery()
    {
        return get_field('logo_gallery');
    }
}
```

---

## Post 154 by @Simeon — 2017-11-27T02:58:07Z

Oh yeah, the code I posted above was working :smiley:

---

## Post 155 by @Simeon — 2017-11-27T02:59:49Z

Another ‘best practice’ question. How do you go about querying the `$post` if it’s not set yet in `app.php`. Say I want to get the featured image, I’ve had to add `$post = get_post();` like this, but I have no idea if I’m doing this right…

```
public function featured_image()
    {
        $post = get_post();
        $featured_image = get_the_post_thumbnail($post->ID, 'large', array('class' => 'img-fluid'));

        return $featured_image;
    }
```

---

## Post 156 by @MWDelaney — 2017-11-27T05:12:30Z

I think you need to use a [static method](https://github.com/soberwp/controller#using-static-methods) for that.

---

## Post 157 by @Simeon — 2017-11-27T05:26:31Z

Not sure about that, adding `static` broke it, but I can make that one function a line shorter at least…

```
public function featured_image()
    {
        $featured_image = get_the_post_thumbnail(get_post()->ID, 'large', array('class' => 'img-fluid'));

        return $featured_image;
    }
```

* * *

Side note, if anyone’s got a working example of an ACF Relationship field with permalink and featured image I’d love to see it. Got me absolutely beat atm.

---

## Post 158 by @Simeon — 2017-11-27T06:17:00Z

This works, but again I’m not sure if this is in the spirit of what Blade was intended for…

```
function services_featured()
  {
    $services_featured = get_field('services_featured');

    return $services_featured;
  }
```

```
@if($services_featured)
      <div class="card-deck">
        @foreach($services_featured as $p)
          <div class="card">
            {!! get_the_post_thumbnail($p->ID, 'card-hdr', array('class' => 'card-hdr-img')) !!}
            <div class="card-body">              
              <h2><a href="{{ get_the_permalink($p->ID) }}">{{ get_the_title($p->ID) }}</a></h2>
            </div>
          </div>
        @endforeach
      </div>
      @endif
```

---

## Post 159 by @Webstractions — 2017-11-27T16:10:44Z

@Simeon Something like this.

```
function services_featured()
{
    $fields = get_field('services_featured');
    $services_featured = [];
    foreach($fields as $field)
    {
        $service = [];
        $service['thumbnail'] = get_the_post_thumbnail( $field->ID, 'card-hdr', ['class' => 'card-hdr-img'] );
        $service['permalink'] = get_the_permalink($field->ID);
        $service['title'] = get_the_title($field->ID);
        $services_featured[] = $service;
    }
    return $services_featured;
}
```

```
@if($services_featured)
      <div class="card-deck">
        @foreach($services_featured as $p)
          <div class="card">
            {!! $p['thumbnail'] !!}
            <div class="card-body">              
              <h2><a href="{{ $p['permalink'] }}">{{ $p['title'] }}</a></h2>
            </div>
          </div>
        @endforeach
      </div>
 @endif
```

---

## Post 160 by @Simeon — 2017-11-27T18:53:42Z

Yeah that’s more like what I had in mind but couldn’t get there. Thanks!!!

---

## Post 161 by @peiche — 2017-12-22T17:19:14Z

@Simeon, I have it working as a static function inside app/controllers/app.php, inside the App class. I modified it a bit:

```
public static function featured_image($class)
{
    $featured_image = get_the_post_thumbnail(get_post()->ID, 'large', array('class' => $class));
    return $featured_image;
}
```

---

## Post 162 by @brandonvhuynh — 2018-05-24T04:20:59Z

Have you been able to work out a more eloquent solution?

---

## Post 163 by @withjacoby — 2018-05-24T06:28:00Z

Use a static function so you can run a function within each layout.

---

## Post 164 by @brandonvhuynh — 2018-05-24T06:41:22Z

Thanks for the response.

I noticed that same variable values are being displayed on different flexible content rows; despite the values in the backed of WP.

How would you go about creating a unique variables inside of the flexible content loop with the controller?

---

## Post 165 by @williharder — 2018-07-26T12:40:14Z

Hey did you end up using this way of getting the name of the current blade template? Because I tried to implement it the exact same way (also using barba.js in my project), but I can’t get it to work. I get the error message “undefined variable: current\_template in …/wp-content/uploads/cache/350a511d5b8c77023912d976ba1f2ffcdbf847ee.php”.

I added the filter in “my-theme/app/filters.php”. Maybe I’m missing something?! A pointer would be much appreciated!

sage version: 9.0.1

---

## Post 166 by @withjacoby — 2018-07-26T12:54:13Z

Are you using Controller?

You should be able to add this to App.php if you’re using Controller.

---

## Post 167 by @williharder — 2018-07-26T13:05:45Z

Hey, I already updated to “soberwp/controller”: “2.0.1” and followed instructions from other threads for the changed file names etc. So I’m able to get data of simple strings with the controller into my views, but not really sure how to use the filter for the name of the current blade template with the controller. That’s why I tried to use the filter method in “app/filters.php”.

---

## Post 168 by @withjacoby — 2018-07-26T13:13:25Z

That’s a good usecase, got some work to finish up, but I’ll take a look at a nicer way of doing this via the App Controller this evening.

---

## Post 169 by @withjacoby — 2018-07-27T09:04:31Z

@williharder this is quite an easy fix for Controller, so I’m going to push a new version over the weekend.

It will solve this [https://github.com/roots/docs/issues/150](https://github.com/roots/docs/issues/150) and [https://github.com/soberwp/controller/issues/80](https://github.com/soberwp/controller/issues/80)

So in summary `add_filter` should work again as expected.

**Update:** Pushed to dev-master for testing.

> <https://github.com/soberwp/controller/commit/8de985147fc1a163702b8a5c60315f5a48942bf9#diff-3840aae95575d417f513143775141e9d>

---

## Post 170 by @withjacoby — 2018-08-01T12:35:01Z

@williharder to take this further, the next release (which I’ll tag in the next few hours), is going to have a `__before` (and `__after`) method which will allow you to interact with Controller params. One of them, is

```
protected $template;
```

So in your specific Controller, you could use this lifecycle event

```
public function __before()
{
    var_dump($this->template);
}
```

---

## Post 171 by @masoninthesis — 2018-09-12T02:39:30Z

I hadn’t needed to learn too much about Blade to stay fairly DRY until now. So I watched the Blade section in this tutorial, and 30-60 minutes of taking notes and watching was so worth it. Really cleared up a couple confusions I had w/ Blade.

I’ve done this guy’s tuts before (on Udemy for Vue.js), and he is one of my favorites.

Pluralsite isn’t free, but they do have free trials (no affiliate link or anything sneaky):

> **[Getting Started with Laravel (PHP Framework) - The Basics](https://www.pluralsight.com/courses/laravel-php-framework-getting-started-the-basics)**
>
> Frameworks like Laravel support you when building web applications that scale. This course teaches the basics about Laravel, how it works, how to use views, controllers and models, and how to connect it all.

---

## Post 172 by @jasonbaciulis — 2018-09-12T07:06:39Z

Thanks, I was also looking to learn better practices, will definitely check out.

---

## Post 173 by @jasonbaciulis — 2018-09-13T20:38:11Z

I also found some blade tutorials on Laracast. Components and slots is a cool feature that is probably overlooked but most: [https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/6](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/6)

---

## Post 174 by @psymeon — 2018-10-16T18:23:49Z

I recently started using [S3-Uploads](https://github.com/humanmade/S3-Uploads) and I run into this issue. Thanks a lot for mentioning this solution, it worked for me as well. Have you found a better way to counter this issue since you last posted your solution? Thanks!

---

## Post 175 by @Log1x — 2018-11-12T01:14:39Z

Thought I’d chime in with my directives package:

> **[Log1x/sage-directives](https://github.com/Log1x/sage-directives)**
>
> A set of Blade directives for use with Roots Sage. - Log1x/sage-directives

Right now there is no documentation and I’m a little pressed on time, but the source code is a quick read to see what is readily available.

For documentation, I will probably just do a MD table or something in the README.md if anyone is feeling froggy. :wink:

---

## Post 176 by @mephilip — 2019-01-15T01:26:06Z

Hey,

Awesome code, I’m using it right now on one of the sites I’m working on. Have a Quick q.

Did you end up having to use WP\_Query for when you wanted pagination? I see get\_posts as not working when you want to use pagination.

---

## Post 177 by @codepuncher — 2019-01-15T21:58:43Z

`get_posts` and `WP_Query` behave differently.

The first will simply grab an array of posts for you to use and manipulate.

Whereas `WP_Query` is more for building out a page to list posts whilst leveraging the rest of the WP API.

In other words: `get_posts` has no relation to `WP_Query` pagination.

Read more: [https://stackoverflow.com/a/24847152/4020364](https://stackoverflow.com/a/24847152/4020364)

---

## Post 178 by @Dennis_Germundal — 2019-02-26T16:58:30Z

The only thing that worked for me was:

```
`add_action('the_post', function() {
    global $template;
    sage('blade')->share('current_template', basename( $template ,'.blade.php' ));
```

});`

---

## Post 179 by @voyou-sbeaulieu — 2019-05-08T18:08:41Z

Hi, we are really trying to understand how to use layouts with @extends / @yield but we ran into a problem during our dev and we can’t figure why it’s not working the ways we want to… Here the stackoverflow : [https://stackoverflow.com/questions/56046544/blade-sage-9-probem-when-multiple-yield-section](https://stackoverflow.com/questions/56046544/blade-sage-9-probem-when-multiple-yield-section)

This forum was full of good ideas and inspire a lots of this stuff maybe someone here can help us understand what we did wrong or why this is happenning!

---

## Post 180 by @joshb — 2020-02-05T02:08:22Z

I still struggle with using ACF Repeater Loops in controllers and I’m wondering if anyone would be interested in breaking it down for me in this specific scenario…

I have a repeater using a list of radio options. Depending on the option selected, an ACF file field is shown to prepopulate button text, or an final option to choose other and enter your own button text and file.

Here’s the loop I’m currently working with but would love to use this properly in a controller. I’ve tried many different ways of doing this but just can’t seem to get it to work properly. Thank you.

```
@if( have_rows('documents') )
  @while ( have_rows('documents') )
    @php the_row();
      $type = get_sub_field('document_type');
      $specifications = get_sub_field('specifications');
      $floor_plans = get_sub_field('floor_plans');
      $survey = get_sub_field('survey');
      $land_use = get_sub_field('land_use');
      $gis_map = get_sub_field('gis_map');
      $parcel_report = get_sub_field('parcel_report');
      $document_title = get_sub_field('document_title');
      $other = get_sub_field('document_file');
    @endphp
    @if ($type == 'specifications')
      <a href="{{ $specifications }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">Specifications</a>
    @elseif ($type == 'floor_plans')
      <a href="{{ $floor_plans }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">Floor Plans</a>
    @elseif ($type == 'survey')
      <a href="{{ $survey }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">Survey</a>
    @elseif ($type == 'land_use')
      <a href="{{ $land_use }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">Land Use</a>
    @elseif ($type == 'gis_map')
      <a href="{{ $gis_map }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">GIS Map</a>
      @elseif ($type == 'parcel_report')
      <a href="{{ $parcel_report }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">Parcel Report</a>
      @elseif ($type == 'other')
      <a href="{{ $other }}" class="flex-1 text-white uppercase no-underline p-4 border border-white m-2">{{ $document_title }}</a>
    @endif
  @endwhile
  @else
    <p class="text-center text-xlg">Sorry, there are no documents associated with this property.</p>
@endif
```
