Best Practice / Resources for Blade

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.

1 Like

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.

1 Like

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. Is the sage/template/global/data filter technique the only way?

Thanks :slight_smile:

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!

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.

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 );

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

1 Like

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

Any hints appreciated :slight_smile:

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] }}

2 Likes

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.

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

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?

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

2 Likes

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.

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/global.php

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

2 Likes

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.

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.

7 Likes

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.

1 Like

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…

1 Like

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.

1 Like

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.