Roots Discourse

Set new layout based on meta field value

Hello guys, I’m really new into sage theme and I’m develop a plugin to create a new meta field into the post type form to activate an alternative layout for certain post .

I changed the layout (“app.blade.php”) for another one. I made these configs in my plugin:

add_filter('single_template', 'switch_layout_template');

function switch_layout_template($single_template) {
	global $post;

	if ($post->post_type == 'post') {
    $value = get_post_meta($post->ID, 'switch_layout_field, true);
    if(!empty($value))
      $single_template = plugin_dir_path( __FILE__ ).'/resources/views/layouts/newlayout.blade.php';
	}
	return $single_template;
}

And add the path for these views into to the views config for Sage.

This works! but doesn’t render the post content. My question is, because I’m crazy about this now, if is a good practice or is there another and a good way to do it?

Thanks so much for the collaboration. Cheers.

Hi @Leben_Lassen,

You’re missing a quote in your code:

$value = get_post_meta($post->ID, 'switch_layout_field, true);

Should be:

$value = get_post_meta($post->ID, 'switch_layout_field', true);

And TBH the way you have it formatted also makes it look a bit like you’re missing braces around your if clauses.

Assuming those two things aren’t related to the problem you’re having… here are a couple of thoughts (all code below is untested).

Without seeing your layout code I can’t say for sure, but if your layout follows the convention set by Sage’s default layout, my guess is that you’re not seeing the post content because you’re only telling WordPress to load the wrapper, not a template that actually renders out the content. WordPress should be loading an actual page or post template, like single.blade.php, not the layout directly. The template will tell Sage what layout to load by using the @extends directive (see the top of any page or post template in Sage). By skipping that step and going right to the layout, the functions that output the content are never being called.

In both cases below, I’m suggesting you move your templating logic from your plugin to your theme. If you don’t want to do that, you may still be able to adapt something below to suit your purposes.

First, if whenever you will be using the alternative layout you’ll always be using it with one specific template (e.g., the template for a specific post type or a custom page template), you can just modify the first line in that template file to extend your alternative layout instead of the default layout. In this case, you wouldn’t need to add a custom option to the editor or use a filter.

This would be the case if you always want to use an alternative layout for a custom movies post type, for example. In that case, you would have single-movies.blade.php with something like this:

For example:

@extends('layouts.movies')

@section('content')
  @while(have_posts()) @php(the_post())
    // custom template code
  @endwhile
@endsection

Second, if the above solution won’t work because you’re mixing and matching with what templates you’ll be using the alternative layout, you can have your theme choose the right layout dynamically based on the field. Here’s a mock up of how you might implement that.

In app/controllers/app.php:

<?php

namespace App;

use Sober\Controller\Controller;

class App extends Controller
{
    // ... the default controller methods (siteName(), title()) here, then your new method

    public function layout()
    {
        return (get_post_type() === 'post' && get_post_meta(get_the_ID(), 'switch_layout_field', true)) ? 'layouts.alternative-layout' : 'layouts.app';
    }
}

Then in any templates where you may want to use either the default layout or the alternative layout, you would use the value from this method.

For example, in single.blade.php:

@extends({{ $layout }})
2 Likes