Creating Upfront templates from Json objects


I have been working with Upfront for the last couple of days and I am starting to get familiar with how it works. I am pretty sure its possible to make page templates from Json objects but I am missing a piece in the puzzle.

Let me explain what I think is going on with Upfront incase I have made any wrong assumptions.

This is my understanding of the workflow:

1. User requests a page
2. Upfront checks the database based on template hierarchy to see if a Json object exists
2.1. If a Json object exists the upfront serializes this Json object to Upfront data model to build the page
2.2. If no Json object exists in database then Upfront serializes the array in the templates layout file
3. Upfront builds the page based on the serialized data model(s)

This is all pretty cool as it means I can easily override pages layout just by writing a Json object to the database.

However, it has a major drawback in that it only works for pages that already exist. If you want to save a layout so that a user can select it when creating a new page then you have to have a template file.

It seems to create template files you drop in a php file named page_tpl-type.php to the child theme.

This file looks something like this:

$layout = Upfront_Output::get_layout(array('specificity' => 'single-page-type'));

echo $layout->apply_layout();

So from the looks of it, all this is doing is initializing a model then making a call to apply_layout().

As the model can be initialized from Json as well as PHP then it is obviously possible for me to create a page in the Upfront GUI editor and save it. Then copy the Json from the database to a string input in the template file and initialize it from Json.

So I have started digging around and trying to piece together how it works but it would be super helpful if someone could just give me the line of code to create a layout from Json.

I've been looking at the to_json() and to_php() methods so it also looks possible to take a Json file, run it through this function to get the PHP array and then do a var_dump to get the array to paste into a template file (although not really necessary once I get it working from the Json object I think, although I guess it may improve performance?).

I am pretty sure anyone familiar with the codebase should know the method call and be able to save me a load of time piecing through everything.

Anyone able to help me out and save me digging through the code all day?

    • Mike

      I tried this way to do it:

      $my_json = "... lots of json pasted from db ... ";
      $json_layout = Upfront_Layout::from_json($my_json);
      $layout = new Upfront_Output($json_layout, get_post($post_id));
      echo $layout->apply_layout();

      It runs without error but it only loads badly formatted text.

      The other way I tried is by setting a breakpoint on from_php and doing var_export in the debugger. I could then in theory go through this and cut and paste these arrays into add_region/add_element methods but that's a major pain in the butt.

      Cmon guys, I know you must have a way of doing this that you use for building your themes. Please share so I can make page templates.

  • Vladislav


    You're on the right track, and what you achieved on your own is so very impressive! What really happens behind the curtains with the page template is when Upfront_Output::get_layout is being called, it first resolves the layout to one from either the database, or template file - this step is very important, as it will allow for showing the default layout version from a file on first go, and also allow for editing and loading the edited/saved layout from database later on. The layouts are by default loaded from the theme's layouts directory, and indicated by the "specificity" argument (this is actually a cascade, where the argument keys can be "type", "item" and "specificity", ordered from most general to most specific). So, the easiest way around this would be to add a layout there, based on one of the layouts already present in the theme. For an example, if you have your layout file in "layouts/single-page-test.php", you can pass this as the specificity key to the parameter in your template, like this:

    $layout = Upfront_Output::get_layout(array('specificity' => 'single-page-test'));

    There are other moving parts, so simply loading layouts from JSON objects isn't all that easy via API at this time. One of our goals is to expose a well-designed and easy to use interface for such usage for advanced users. At the moment though, the easiest option is to load a custom-created layout from the page template. I hope this helped.

    • Mike

      I've been working on this all day and I'm still convinced it's possible, can you have another look at this please.

      When you use:

      $layout = Upfront_Output::get_layout(array('specificity' => 'my-slug'));

      it works perfectly when directing to a saved database page. The HTML output is perfect.

      The only thing that doesn't get output is the wrapper CSS. This is because in the saved database object there is no wrapper entry.

      Where are the wrappers stored in the database?

      Can you have another look at this as it would work perfectly I think if the Json object had wrapper info.

  • Mike

    So lets say I do this:

    $layout = Upfront_Output::get_layout(
    		'specificity' => 'single-page-2702',
    		'item' => 'single-page',
    		'type' => 'single'
    echo $layout->apply_layout();

    Page 2702 is a new page created by me in Upfront using default template. I then create a second page using this template specified in the PHP.

    I have set break points at the end "echo $layout.." and then used a text diff tool to see where the difference is and both outputs are identical.

    I thought for a brief moment that this data might be being serialized to the upfront_layour_rvsn posts so I deleted them all but no joy.

    I have also checked post meta, nothing in there.

    Why do margin values load with one and not the other?

    • Vladislav


      That's right - the styles for a particular layout are being generated and loaded from Upfront_StylesheetMain::load_styles() method. Since this request is an AJAX request, it has no notion of how the layout is being overridden in a template and resolves to how it normally would for a page. To make it output the styles for specific elements/regions present in your overridden layout, you'll possibly want to hook up to "upfront_prepare_theme_styles" filter (you can check Upfront_ChildTheme::prepareThemeStyles() method to see how that works for child themes). Like I said, the whole process is pretty complex at the moment to do manually via JSON. The way I suggested in my previous post is the easiest way to achieve custom layouts in a page template at the moment.

      • Mike

        Yeah, I spent the day yesterday writing out arrays and hitting refresh in browser. The progress is real slow so I keep looking for a quicker way (some may call it procrastinating, I prefer to call it resourceful laziness).

        I see what you mean, Upfront_ChildTheme::prepareThemeStyles() is hooked up to the upfront_prepare_theme_styles filter.

        I stepped through both of those methods and they both bring back identical data for both my pages. Where the path diverges is this block of code in load_styles():

        if (false === $base_only) {
        			$grid = Upfront_Grid::get_grid();
        			$preprocessor = new Upfront_StylePreprocessor($grid, $layout);
        			$style = $this->prepare_typography_styles($layout, $grid);
        			$style .= $preprocessor->process();

        $style .= $preprocessor->process(); adds in the user generated layouts. To be precise it is the apply_breakpoints($layout) method that creates the CSS wrapper value from the Upfront_Layout object.

        I ran the diff tool on the return value and I can see it's almost identical, it just lacks the user generated wrappers when I alter the specificity.

        The line that adds the user generated data is:

        $point_css .= $this->_apply_modules($region, $region_col, false);

        The reason it isn't working is because the data is missing from the $region variable.

        So I compared both $layout variables being passed and realised that it is missing from there.

        I backtracked and can see the $layout is being loaded here:

        $layout = apply_filters('upfront-style-base_layout', Upfront_Layout::get_instance());

        A little more digging and I find what looks to be the culprit line:

        $regions = upfront_get_default_layout(self::$cascade, self::$layout_slug, $add_global_regions);

        I'm digging deeper trying to pinpoint the exact part of code that loads the data in one but not the other but getting a little confused now. Made this post to keep track of what I am doing.

      • Mike

        I figured it out!

        The upfront layout object is created twice. Once for the wordpress routed request and once for the ajax request.

        On the first load the specificity is set by template. On the second load it is set by this line:

        $id = $storage_key . '-' . $cascade[$o];

        This means that this next line fails to find the correct Json object:

        $data = json_decode( get_option($id, json_encode(array())), true );

        So I did a little test and replaced that line with:

        $id = "Template-my-slug";

        And it worked!

        Obviously that's not a solution, it was just to see if all the layout data came through and it did. I am not 100% sure how I will use this in my workflow but I am getting more familiar with the PHP code now.


        Can I get access to the beta build? I'd really like to keep an eye on what's changing before release so I don't get myself in too much trouble or waste time.

  • Mike

    Got it working :slight_smile:

    It formats a var_export into upfront_create_region and it appears to work!

    1. Design region in GUI
    2. Select region in plugin and it outputs the PHP code to paste into a template file.

    It was actually really simple, the time was taken all pretty much understanding someone else's code. There may be some bugs but on first glance it seems to work. I'll test it out properly tomorrow.

    Do you guys really write those arrays out by hand???

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.