Outputting A Custom Partial from Controller to View

So, for my template, I’m creating a block of code that runs custom “Modules”. Basically, they are a custom post type, with fields built in ACF. Each of these modules has their own Blade template (e.g. /resources/views/modules/brandwindow.blade.php).

I’ve also created a Blade template for a custom post type called “Modular Page”. On this template, I handle all the calls for each and any module called in a loop. I want to be able to handle this login in a controller, however. So, I created a Controller called “LoadModules” that will handle that request.

I’m having some difficulty calling a Blade template from a Controller, though. In a function GetModules(), I loop through the ACF repeater to see which module I need to load, and then supply all the relevant fields with another Controller specific to that Module (e.g. if module = ‘bwindow’, Call BrandWindow->BrandWindowFields). This returns an array which I can then pass into a View.

I’ve added the View class to the top of the Controller (like you would in Laravel), but I’m pretty sure I’m doing something wrong here. I’m getting the following error:
Class ‘View’ not found in …\app\Controllers\LoadModules.php on line 25

Here’s my Controller code:

public static function GetModules()
{
    $brand_window_loader = new BrandWindow;
    $module_array = get_sub_field('content_type');
    if ($module_array == 'bwindow') {
        // Do Brand Window Stuff
        $windows = $brand_window_loader->GetBrandWindows();
        $output = '';
        foreach ( $windows as $window ){
            $feild_array = $brand_window_loader->BrandWindowFields($window);
            $output .= View::make('modules.brandwindow', $feild_array);
        }
        return $output;
    } elseif ($module_array == 'blogfeed') {
        // Do Blog Feed Stuff
        return $module_array;
    }
}

Line 25, is throwing the error which is:

$output .= View::make('modules.brandwindow', $feild_array);

The $brand_window_loader->BrandWindowFields($window) is just an array of keyed values it pulls from ACF using the ID of the post.

'title' => 'Title',
'sub_text' => 'Sub Text',
'url' => 'http://example.com'
ETC.

The error is obviously related to the “View” class not existing, so I’m wondering if I’ve namespaced or the View class does not exist with Sage 9/Bedrock. If that’s true, what is the best way to include a Blade template from a Controller?

Thanks

To render a Blade template manually (which seems to be what you’re trying to do) you can use the App\template() function. AFAIK View is not available in Sage.

It’s unclear to me why you want to render a template from the Controller here, though. It seems like it would be simpler to use the controller to generate an array of all the content you need, then iterate over that in a Blade and @include the necessary partials.

Ah yes,

I changed the line in question to:

$output .= \App\template(‘modules.brandwindow’, $feild_array);

Which is now outputting the template. However, it’s outputting in plaintext. Any ideas?

And to answer your question, honestly, I just want to clean up the code and maintain a MVC model for my project. I can fully create this stuff in a “if,else” loop on a blade template (in fact, I already did), but I just wanted to take it a step further.

Without seeing your code or your errors it’s difficult to diagnose what might be wrong.

No errors, just outputting in plaintext, not in HTML. For Example:

<div class=“brand-window” style=“background-image: url(//localhost:3000/app/uploads/2018/09/720.jpg)”> <a class=“brand-window-touch” href="//localhost:3000/index.php/2018/09/13/focus-on-content/"></a> <div class=“brand-window-content container”> <div class=“brand-window-text-container”> <div class=“brand-window-title”> <span class=“highlight-wrap”>New and Exciting</span> </div> <div class=“brand-window-sub-container container clear”> <div class=“brand-window-subtext”>Launching Jan 01</div> <div class=“brand-window-button”> <a href="//localhost:3000/index.php/2018/09/13/focus-on-content/">More Info<i class=“fa fa-chevron-right”></i></a> </div> </div> </div>

The only code that was changed was the line you suggested I change.

$output .= \App\template(‘modules.brandwindow’, $feild_array);

Where and now is that text appearing? It’s not clear to me where and how data is being ultimately passed to your blades, since the only code you’ve posted is a static function which IIRC is not passed to Blade as a variable. Is that content being echoed in an existing Blade template? It looks like you’re outputting it with {{ }} which will escape the text passed to it. You need to use {!! !!}, which echoes exactly what’s passed to it.

That was it. I noticed it formatted correctly when I switched my return to an echo. I didn’t realize the functionality of {!! !!}. I switched back my return and then used {!! !!} in the blade template and it’s outputting correctly now.

Thanks!

Just to be thorough (and to answer your question), here is how my templates are connected.

front-page.blade.php

@extends('layouts.app')

@section('content')
  @while(have_posts()) @php the_post() @endphp
    @include('partials.modules')
    @include('partials.content-front-page')
  @endwhile
@endsection

partials/modules.blade.php

@while ( have_rows('content_row') )
    @php the_row(); @endphp
    {!! LoadModules::GetModules() !!}
@endwhile

LoadModules.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class LoadModules extends Controller
{
    protected $acf = true;
    
public static function GetModules()
{
    $brand_window_loader = new BrandWindow;
    $module_array = get_sub_field('content_type');
    if ($module_array == 'bwindow') {
        // Do Brand Window Stuff
        $windows = $brand_window_loader->GetBrandWindows();
        $output = '';
        foreach ( $windows as $window ){
            $feild_array = $brand_window_loader->BrandWindowFields($window);
            $output .= \App\template('modules.brandwindow', $feild_array);
        }
        return $output;
    } elseif ($module_array == 'blogfeed') {
        // Do Blog Feed Stuff
        $keyword_array = ['keywords' => 'General'];
        return \App\template('modules.blogfeed', $keyword_array);
    }
}
}

modules/brandwindow.blade.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class BrandWindow extends Controller
{
    protected $acf = true;

    public static function GetBrandWindows()
    {
        $window_array = get_sub_field('brand_window_controller');
        return $window_array;
    }

    public static function BrandWindowFields($window)
    {
        $window_fields = get_fields($window->ID);
        //return $window_fields;
        
        if ($window_fields['bwindow_internal_page_toggle'][0] == '1') {
            $window_url = $window_fields['bwindow_page_link'];
        } else {
            $window_url = $window_fields['bwindow_url'];
        }

        return [
            'title'     => $window_fields['bwindow_main_text'],
            'sub_text'  => $window_fields['bwindow_sub_text'],
            'url'       => $window_url,
            'url_text'  => $window_fields['bwindow_url_text'],
            'image'     => $window_fields['bwindow_image']['url']
        ];
    }
}

And then modules/brandwindow.blade.php calls the following in different HTML elements on page:

{{ $title }}
{{ $sub_text}}
{{ $url}}
{{ $url_text}}
{{ $image}}

Hopefully this helps someone like me trying to set up a system like this in the future. :smile:

Glad you got it figured out! The official Blade docs are usually a pretty good resource: Sage supports essentially all Blade features that don’t involve doing something with a class. (I’m not sure exactly what version of Blade we’re on, though.)

Admittedly I don’t fully understand your use case, but I feel like you could simplify your Controllers and Blades a bit to make them easier to read, maybe something a little like this:

/** Controller */
public function modules()
{
    global $wp_query;
    $data = false;
    
    if ($wp_query->post_count > 0) {
        $data = array_map(function ($module) {
            return array(
                'image'   => wp_get_attachment_image(
                    get_post_thumbnail_id($module->ID),
                    'post_featured_image_400',
                    false
                ),
                'module_type' => $module->content_type ?? false,
                'title'     => $module->bwindow_main_text ?? false,
                'sub_text'  => $module->bwindow_sub_text ?? false,
                'url'       => $module->url ?? false,
                'url_text'  => $module->bwindow_url_text ?? false,
                'window_url' => $module->bwindow_internal_page_toggle[0] == '1'
                    ? $module->bwindow_page_link
                    : $module->url,
            );
        }, $wp_query->posts);
    }
    
    return $data;
}
/** Blade */
@extends('layouts.app')

@section('content')
    @while(have_posts()) @php the_post() @endphp
        @foreach($modules as $module)
            @include('partials.'.$module['module_type'], $module)
        @include('partials.content-front-page')
    @endwhile
@endsection

Thanks for the ideas, my code definitely needs some optimization. To be honest, I’m new to Sage/Roots, so all the advice is appreciated.

I’ll make an optimization re-write pass at my code once I get all the functionality in place.

Thanks again :+1: