Jump to content
Sephiroth

Templating Style in Processwire: Twig Templating

Recommended Posts

Hi, So today I will writing a small tutorial on developing templates in Processwire using Twig Template, Processwire is a highly flexible CMS which gives developers/designers/users options and allows easy extension of the platform. So here goes the tutorial 

What is Twig Template ?

Simply put in my own words, Twig is a modern templating engine that compiles down to PHP code, unlike PHP, Twig is clean on the eyes , flexible and also quite *easy* to have dynamic layout site with ease ,without pulling your hair out. Twig is trusted by various platforms. It was created by the guys behind Symfony.

Take this code as an example

{% for user in users %}
    <h1>* {{ user }}</h1>
{% endfor %}

This will simply be the equivalent in PHP World

<?php

$userArray = ["Nigeria","Russia"];

foreach($userArray as $user):
?>
<h1><?= $user ?></h1>
<?php
endforeach;

The PHP code though looks simple enough however, you start to notice that you have to be concerned about the PHP tags by ensuring they are closed  properly , most times projects gets bigger and comes complex and harder to read/grasp, and also in PHP you can explicitly create variables in the template making it very hard to read as it grows and prone to getting messy WordPress is a major culprit when it comes to that regard.

Have you ever wanted to created separate layouts for different pages and  break your sites into different parts e.g Sidebar, Comment Section, Header Section ? the regular approach would be to create individual pages for each section and simply add them as templates for the pages and with time, you can end up having tons of templates, however Twig allows you to easily inherit templates and also override the templates where you can inject content into the block easily. Don't worry if you don't understand the concept, the following parts will explain with an example of how to easily inherit layouts and templates.

Layout

<!DOCTYPE html>
<html lang="en">

<head>
   {{include("layout/elements/header.twig")}}
</head>

<body>
 
    <div class="container-fluid" id="minimal">
        <header id="pageIntro">
            <div class="bio_panel">
                <div class="bio_section col-md-6">
                    <h1>Okeowo Aderemi</h1>
                    <h2>{{ page.body }}</h2>
                </div>
            </div>
            <div class="clearfix"></div>


        </header>
        <section id="page-body">
            <div class="container">
                <div id="intro" class="col-md-7 col-lg-7">
                    <h1>About me</h1>
                    <h2>
                        {{ page.summary }}
                    </h2>
                </div>
              {block name="content"}{/block}
             
                    <a style="font-size:1.799783em; font-style:italic;color:#d29c23" href="{{pages.get('/notes').url }}">Read more articles</a>
                </div>
                <div class="clearfix"></div>
            </div>

        </section>

    </div>
    <footer>
        <div class="header-container headroom headroom--not-top headroom--pinned" id="header-container">

   {{include("layout/elements/footer.twig")}}           

        </div>
    </footer>
</body>

</html>

This is basically a layout where we specify blocks and include other templates for the page, don't panic if you don't understand what is going on, I will simply break down the weird part as follows:

Include

This basically is similar to native PHP 'include', as it's name suggests it simply includes the templates and injects the content into the layout , nothing out of the ordinary here if you are already familiar with php's include function.

{{ output }}

This simply evaluates the expression and prints the value, this  evaluate expressions, functions that return contents , in my own short words it's basically the same as <?= output ?> except for the fact that it's cleaner to read.

{% expression %}

unlike the previous this executes statements such as for loops and other Twig statements.

{% for characters in attack_on_titans %}
<h1> {{characters}} </h1>
                {% endfor %}

This  executes a for loop and within the for loop, it creates a context to which variables in that context can be referenced and evaluated, unlike dealing with the opening and closing PHP tags, Twig simply blends in with markup and makes it really quick to read. 

I will simply post the contents of both the header and footer so you can see the content of what is included in the layout

header.php

<meta charset="utf-8"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>
    {{ page.title }}
</title>
<link href=" {{config.urls.templates }}assets/css/bootstrap.min.css" rel="stylesheet"/>
<link href="{{config.urls.templates }}assets/css/main.min.css" rel="stylesheet"/>
<link rel='stylesheet' type='text/css' href='{{config.urls.FieldtypeComments}}comments.css' />
<link rel="stylesheet" href="{{config.urls.siteModules}}InputfieldCKEditor/plugins/codesnippet/lib/highlight/styles/vs.css">
<script type="text/javascript" src="{{config.urls.siteModules}}InputfieldCKEditor/plugins/codesnippet/lib/highlight/highlight.pack.js"></script>

<script src="{{config.urls.templates }}assets/js/vendors/jquery-1.11.3.min.js">
</script>
<script src="{{config.urls.templates }}assets/js/vendors/bootstrap.min.js">
</script>
<script src="{{config.urls.FieldtypeComments}}comments.js"></script>
<link rel="stylesheet" type='text/css' href="{{config.urls.templates}}js/jquery.fancybox.min.css">
 <script src="{{config.urls.templates}}js/jquery.fancybox.min.js"></script>
 {block name="javascriptcodes"}{/block}

footer.php

 <nav class="site-nav pull-right">
                <div class="trigger">
                    <a class="page-link" href="{{pages.get('/about').url}}">
                        <span>{</span> About
                        <span>}</span>
                    </a>
                    <a class="page-link" href="{{pages.get('/notes').url}}">
                        <span>{</span> Journals
                        <span>}</span>
                    </a>
               
                    <a class="page-link" target="_blank" href="https://ng.linkedin.com/in/okeowo-aderemi-82b75730">
                        <span>{</span> Linkedin
                        <span>}</span>
                    </a>
                    <a class="twitter page-link" target="_blank" href="https://twitter.com/qtguru">
                        <span>{</span> Twitter
                        <span>}</span>

                    </a>
                </div>
            </nav>

There's nothing special here, other than twig simply injecting these fragments into the main layout , the next part is the most interesting and important concept and benefit that Twig has to offer

{% block content %}{% endblock %}

This tag simply creates a placeholder in which the content would be provided by the template inheriting this layout, in lay terms it simply means child templates will provide content for that block, the 'content' simply uses the name 'content' to refer to that specific block, so assuming we were to inherit this template it would simply look like this.

Inheriting Template Layout

{% extends 'layout/blog.twig' %}
{% block content %}
<div class="container blog-container">
    <section class="blog">
        <header class="blog-header">
            <h1>
                {{page.title}}
            </h1>
            <h5 class="blog_date">
                {{page.published|date("F d, Y")}} 
            </h5>
            <br>
            </br>
        </header>
        <div class="blog_content">
            <hr class="small" />
             {{page.body}}
             <hr class="small" />

        </div>
    </section>
</div>
{% endblock %}

{% block nav %}
 <div class="col-md-4 col-xs-4 col-sm-4 prev-nav">
                        <a href="{{page.prev.url}}">
                            ← Prev
                        </a>
                    </div>
                    <div class="col-md-4 col-xs-4 col-sm-4 home-nav">
                        <a href="{{homepage.url}}">
                            Home
                        </a>
                    </div>
                    <div class="col-md-4 col-xs-4 col-sm-4 next-nav">
                        <a href="{{page.next.url}}">
                            Next →
                        </a>
                    </div>
{% endblock %}

In this snippet you can easily notice how each blocks previously created in the header and layout are simply referenced by their names, by now you will notice that twig doesn't care how you arrange the order of each block, all Twig does is to get the contents for each blocks in the child templates and inject them in the layout theme, this allows flexible templating and also extending other layouts with ease.

Twig in Processwire

Thanks to @Wanze we have a Twig Module for Processwire and it's currently what i use to build PW solutions to clients

https://modules.processwire.com/modules/template-engine-twig/

The Modules makes it easy to not only use Twig in PW but also specify folders to which it reads the twig templates, and also injects Processwire objects into it, which is why i can easily make reference to the Pages object, another useful feature in this module is that you can use your existing template files to serve as the data provider which will supply the data to be used for twig template.

take for example, assuming I wanted the homepage to display the top six blog posts on it, TemplateEngineTwig will simply load the home.php ( Depending on what you set as the template), it is also important that your twig file bears the same name as your template name e.g home.php will render into home.twig here is an example to further explain my point.

home.php

<?php
 
  //Get the Top 6 Blog Posts
  $found=$pages->find("limit=6,include=hidden,template=blog-post,sort=-blog_date");
  $view->set("posts",$found);

 

The $view variable is the TemplateEngine which in this case would be Twig, the set method simply creates a variables posts which holds the data of the blog posts, the method allows our template 'blog.twig' to simply reference the 'posts' variable in Twig Context. Here is the content of the 'blog.twig' template

blog.tpl

{% extends 'layout/blog.twig' %}
{% block content %}
   <div class="block_articles col-md-5 col-lg-5">
                    {% for post in posts %}
                    <div class="article_listing">
                        <span class="article_date"> {{post.published}}</span>
                        <h2 class="article_title">
                            <a href="{{post.url}}">{{post.title}}</a>
                        </h2>
                    </div>
		{% endfor %}
{% endblock %}

So home.php sets the data to be used in home.tpl once Twig processes the templates and generates the output, twig takes the output from the block and injects it in the appriopriate block in the layout, this makes Processwire templating more flexible and fun to work with. 

The major advantage this has; is that you can easily inherit layouts and provide contents for them with ease, without the need of running into confusions when handling complex layout issues,an example could be providing an administrator dashboard for users on the template side without allowing users into the Processwire back-end. You can also come up with several layouts and reusable templates.

 

Feel free to ask questions and any concerns  in this approach or any errors I might have made or overlooked.

Thanks

 

 

 

  • Like 20
  • Thanks 2

Share this post


Link to post
Share on other sites

Pls tell us, what is the advantage of twig templating over pure php and using the delayed output strategy with markup regions?

Share this post


Link to post
Share on other sites

I'm not using twig but latte but the main advantages are sophisticated template inheritence, filters, reusable blocks/partials, etc, and after all, more readable and maintainable code. Backdraws are the small overhead and some extra complexity, of course the latter disappears when you get used to it.

Markup regions is in my opinion a very simple templating implementation. This works fine if you don't need any of those extra features, and in case of template engines you can more easily find help if you are stuck.

Speaking of myself, I made only my first PW project with pure PHP about 3 years ago, then all with latte.

  • Like 3

Share this post


Link to post
Share on other sites
6 hours ago, pideluxe said:

Pls tell us, what is the advantage of twig templating over pure php and using the delayed output strategy with markup regions?

"delayed output strategy" to me is the same as concatenation, it easily gets messy, hard and difficult to follow, not exactly easy to inherit templates or layouts.

It might work but it comes at the cost of readability and how easy it is in making mistakes.

 Twig Template makes it easier to read ,the only disadvantage I can bring up is that, you cannot instantiate a class inside the template, you must pass a reference of an object to it, then again, your template must not be tied to a code, it should simply take a value it expects and evaluate from that. It makes things really easy to read. 

As for performance it compiles down to php templates, it only compiles when the source has been changed. 

 

Share this post


Link to post
Share on other sites
6 hours ago, tpr said:

I'm not using twig but latte but the main advantages are sophisticated template inheritence, filters, reusable blocks/partials, etc, and after all, more readable and maintainable code. Backdraws are the small overhead and some extra complexity, of course the latter disappears when you get used to it.

Markup regions is in my opinion a very simple templating implementation. This works fine if you don't need any of those extra features, and in case of template engines you can more easily find help if you are stuck.

Speaking of myself, I made only my first PW project with pure PHP about 3 years ago, then all with latte.

I just looked at Latte and it's very clean to read, it looks so similar to Twig, I was using Smarty before but Twig is 100% OOP and extending it is cleaner compared to Smarty, I will give Natte Latte a shot later on. 

  • Like 1

Share this post


Link to post
Share on other sites
5 hours ago, Sephiroth said:

"delayed output strategy" to me is the same as concatenation

Delayed output is not about concatenation but storing rendered html in a variable to be output later on. Eg:

<?php
$output = wireRenderFile("./partials/partial.php", array('page' => $page));
//lost of other code :)
echo $output;

Ryan prefers concatenation to wireRenderFile. I prefer wireRenderFile to concatenation, for example.

  • Like 1

Share this post


Link to post
Share on other sites

I used delayed output and markup regions to make clear, they are just other concepts of templating (engines). Delayed output-strategy is about inheritance and markup regions are the so called blocks in twig. Templating in other languages/engines than php is about using other syntax and replacing php-tags with something else, e.g. {%...%} for twig... 

And for terms of reusability: If you are using different fields, you cannot reuse your twig-files, or am i missing something here?

Share this post


Link to post
Share on other sites

Twig doesn't know what a field is, all it expects are variables which are passed to the twig templates from the processwire php files based on the Twig module. Let's take for example the side template in twig, I can have an array of posts which will render the post in a list manner. All I simply need to do is get a list of post and set it with a variable name for that template and the twig template simply renders it based on the variable passed. Besides at the end of the day Twig is basically still compiles to php so it's nothing unique just another layer. 

Share this post


Link to post
Share on other sites
On 3/6/2018 at 9:09 PM, Sephiroth said:

{block name="content"}{/block}

Hello Sephiroth,

Thank you for your tutorial, it is very precious although this code above does not work for me.
I had

{% block content %}
{% endblock %}

which had no problems but did not display the block content.

Thank you for any help.

 

Sten

Share this post


Link to post
Share on other sites
On 6/10/2018 at 8:42 AM, Sten said:

Hello Sephiroth,

Thank you for your tutorial, it is very precious although this code above does not work for me.
I had

{% block content %}
{% endblock %}

which had no problems but did not display the block content.

Thank you for any help.

 

Sten

{block name="content"}{/block}

Sorry about that, that was a smarty template, my brain went into Smarty mode the correct syntax is what you provided, in your layout where you arr inheritting from, ensure you have something like this 
 

{%  block content %} {%  endblock %}

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By calago
      after the migration to version 3.0.145 our export templates all of a sudden dont work properly, 
      we have a functionality where we use a boiler template with a set of fields. for some reason since the upgrade when we select the export template to export it. it wont show any of the fields added after the migration, 

      as you can see the offer certificate remarks field has been added to the export, 
      but when we select it it wont come trough

    • By MoritzLost
      I have recently started to integrate Twig in my ProcessWire projects to have a better separation between logic and views as well as have cleaner, smaller template files as opposed to large multi-purpose PHP-templates. Though there is a Twig module, I have opted to initialize twig manually to have more control over the structure and settings of the twig environment. This is certainly not required to get started, but I find that having no "secret sauce" gives the me as a developer more agency over my code structure, and better insights into how the internals of the libraries I'm using work.
      Framework like Drupal or Craft have their own Twig integration, which comes with some opinionated standards on how to organize your templates. Since Twig is not native to ProcessWire, integrating Twig requires one to build a solid template structure to be able to keep adding pages and partials without repeating oneself or having templates grow to unwieldy proportions. This will be an (opinionated) guide on how to organize your own flexible, extensible template system with ProcessWire and Twig, based on the system I developed for some projects at work.
      Somehow this post got way too long, so I'm splitting it in two parts. I will cover the following topics:
      Part 1: Extendible template structures How to initialize a custom twig environment and integrate it into ProcessWire How to build an extendible base template for pages, and overwrite it for different ProcessWire templates with custom layouts and logic How to build custom section templates based on layout regions and Repeater Matrix content sections Part 2: Custom functionality and integrations How to customize and add functionality to the twig environment How to bundle your custom functionality into a reusable library Thoughts on handling translations A drop-in template & functions for responsive images as a bonus However, I will not include a general introduction to the Twig language. If you are unfamiliar with Twig, read the Twig guide for Template Designers and Twig for Developers and then come back to this tutorial.
      That's a lot of stuff, so let's get started 🙂
      Initializing the Twig environment
      First, we need to install Twig. If you set up your site as described in my tutorial on setting up Composer, you can simply install it as a dependency:
      composer require "twig/twig:^2.0" I'll initialize the twig environment inside a prependTemplateFile and call the main render function inside the appendTemplateFile. You can use this in your config.php:
      $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; Twig needs two things: A FilesystemLoader to load the templates and an Environment to render them. The FilesystemLoader needs the path to the twig template folder. I'll put my templates inside site/twig:
      $twig_main_dir = $config->paths->site . 'twig'; $twig_loader = new \Twig\Loader\FilesystemLoader($twig_main_dir); As for the environment, there are a few options to consider:
      $twig_env = new \Twig\Environment( $twig_loader, [ 'cache' => $config->paths->cache . 'twig', 'debug' => $config->debug, 'auto_reload' => $config->debug, 'strict_variables' => false, 'autoescape' => true, ] ); if ($config->debug) { $twig_env->addExtension(new \Twig\Extension\DebugExtension()); } Make sure to include a cache directory, or twig can't cache the compiled templates. The development settings (debug, auto_reload) will be dependent on the ProcessWire debug mode. I turned strict_variables off, since it's easier to check for non-existing and non-empty fields with some parts of the ProcessWire API. You need to decide on an escaping strategy. You can either use the autoescape function of twig, or use textformatters to filter out HTML tags (you can't use both, as it will double escape entities, which will result in a broken frontend). I'm using twig's inbuilt autoescaping, as it's more secure and I don't have to add the HTML entities filter for every single field. This means pretty much no field should use any entity encoding textformatter. I also added the Debug Extension when $config->debug is active. This way, you can use the dump function, which makes debugging templates much easier. Now, all that's left is to add a few handy global variables that all templates will have access to, and initialize an empty array to hold additional variables defined by the individual ProcessWire templates.
      // add the most important fuel variables to the environment foreach (['page', 'pages', 'config', 'user', 'languages', 'sanitizer'] as $variable) { $twig_env->addGlobal($variable, wire($variable)); }; $twig_env->addGlobal('homepage', $pages->get('/')); $twig_env->addGlobal('settings', $pages->get('/site-settings/')); // each template can add custom variables to this, it // will be passed down to the page template $variables = []; This includes most common fuel variables from ProcessWire, but not all of them. You could also just iterate over all fuel variables and add them all, but I prefer to include only those I will actually need in my templates. The "settings" variable I'm including is simply one page that holds a couple of common settings specific to the site, such as the site logo and site name.
      Page templates
      By default, ProcessWire loads a PHP file in the site/templates folder with the same name of the template of the current page; so for a project template/page, that would be site/templates/project.php. In this setup, those files will only include logic and preprocessing that is required for the current page, while the Twig templates will be responsible for actually rendering the markup. We'll get back to the PHP template file later, but for the moment, it can be empty (it just needs to exist, otherwise ProcessWire won't load the page at all).
      For our main template, we want to have a base html skeleton that all sites inherit, as well as multiple default regions (header, navigation, content, footer, ...) that each template can overwrite as needed. I'll make heavy use of block inheritance for this, so make sure you understand how that works in twig.
      For example, here's a simplified version of the html skeleton I used for a recent project:
      {# site/twig/pages/page.twig #} <!doctype html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}{{ '%s | %s'|format(page.get('title'), homepage.title) }}{% endblock %}</title> <link rel="stylesheet" type="text/css" href="{{ config.urls.site }}css/main.css"> </head> <body class="{{ page.template }}"> {% block navigation %}{{ include("components/navigation.twig") }}{% endblock %} {% block header %}{{ include("components/header.twig") }}{% endblock %} {% block before_content %}{% endblock %} {% block content %} {# Default content #} {% endblock %} {% block after_content %}{% endblock %} {% block footer %}{{ include("components/footer.twig") }}{% endblock %} </body> </html> All layout regions are defined as twig blocks, so each page template can override them individually, without having to touch those it doesn't need. I'll fill the content block with default content soon, but for now this will do. Now, templates for our content types can just extend this base. This is the template for the homepage:
      {# site/twig/templates/pages/page--home.twig #} {% extends "pages/page.twig" %} {# No pipe-seperated site name on the homepage #} {% block title page.get('title') %} {# The default header isn't used on the homepage #} {% block header %}{% endblock %} {# The homepage has a custom slider instead of the normal header #} {% block before_content %} {{ include('sections/section--homepage-slider.twig', { classes: ['section--homepage-slider'] }) }} {% endblock %} Note that I don't do most of the actual html markup in the page templates, but in individual section templates (e.g. section--homepage-slider.twig) that can be reused across content types. More on this in the next section.
      We still need to actually render the template. The page template (which will be the entry point for twig) will be loaded in our _main.php, which we defined as the appendTemplateFile earlier, so it will always be included after the template specific PHP file.
      $template_file = 'pages/page--' . $page->template->name . '.twig'; $twig_template = file_exists($twig_main_dir . '/' . $template_file) ? $template_file : 'pages/page.twig'; echo $twig_env->render($twig_template, $variables); This function checks if a specific template for the current content type exists (e.g. pages/page--home.twig) and falls back to the default page template if it doesn't (e.g. pages/page.twig). This way, if you want a blank slate for a specific content type, you can just write a twig template that doesn't extend page.twig, and you will get a blank page ready to be filled with whatever you want.
      Note that it passes the $variables we initialized in the _init.php. This way, if you need to do any preprocessing or data crunching for this request, you can do it inside the PHP template and include the results in the $variables array.
      At this point, you can start building your default components (header, footer, navigation, et c.) and they will be included on every site that extends the base page template.
      Custom sections
      Now we've done a great deal of setup but haven't actually written much markup yet. But now that we have a solid foundation, we can add layout components very easily. For most of my projects, I use the brilliant Repeater Matrix module to set up dynamic content sections / blocks (this is not the focus of this tutorial, here's a detailed explanation). The module does have it's own built-in template file structure to render it's blocks, but since it won't work with my Twig setup, I'll create some custom twig templates for this. The approach will be the same as with the page template itself: create a "base" section template that includes some boilerplate HTML for recurring markup (such as a container element to wrap the section content in) and defines sections that can be overwritted by section-specific templates. First, let's create a template that will iterate over our the Repeater Matrix field (here it's called sections) and include the relevant template for each repeater matrix type:
      {# components/sections.twig #} {% for section in page.sections %} {% set template = 'sections/section--' ~ section.type ~ '.twig' %} {{ include( [template, 'sections/section.twig'], { section: section }, with_context = false ) }} {% endfor %} Note that the array syntax in the include function tells Twig to render the first template that exists. So for a section called downloads, it will look look for the template sections/section--downloads.twig and fallback to the generic sections/section.twig. The generic section template will only include the fields that are common to all sections. In my case, each section will have a headline (section_headline) and a select field to choose a background colour (section_background) :
      {# sections/section.twig #} {% set section_classes = [ 'section', section.type ? 'section--' ~ section.type, section.section_background.first.value ? 'section--' ~ section.section_background.first.value ] %} <div class="{{ section_classes|join(' ')|trim }}"> <section class="container"> {% block section_headline %} {% if section.section_headline %} <h2 class="section__headline">{{ section.section_headline }}</h2> {% endif %} {% endblock %} {% block section_content %} {{ section.type }} {% endblock %} </section> </div> This section template generates classes based on the section type and background colour (for example: section section--downloads section--green) so that I can add corresponding styling with CSS / SASS. The specific templates for each section will extend this base template and fill the block section_content with their custom markup. For example, for our downloads section (assuming it contains a multivalue files field download_files):
      {# sections/section--download.twig #} {% extends "sections/section.twig" %} {% block section_content %} <ul class="downloads"> {% for download in section.download_files %} <li class="downloads__row"> <a href="{{ download.file.url }}" download class="downloads__link"> {{ download.description ?: download.basename }} </a> </li> {% endfor %} </ul> {% endblock %} It took some setup, but now every section needs only care about their own unique fields and markup without having to include repetitive boilerplate markup. And it's still completely extensible: If you need, for example, a full-width block, you can just not extend the base section template and get a clean slate. Also, you can always go back to the base template and add more blocks as needed, without having to touch all the other sections. By the way, you can also extend the base section template from everywhere you want, not only from repeater matrix types.
      Now we only need to include the sections component inside the page template
      {# pages/page.twig #} {% block content %} {% if page.hasField('sections') and page.sections.count %} {{ include('components/sections.twig' }} {% endif %} {% endblock %} Conclusion
      This first part was mostly about a clean environment setup and template structure. By now you've probably got a good grasp on how I organize my twig templates into folders, depending on their role and importance:
      blocks: This contains reusable blocks that will be included many times, such as a responsive image block or a link block. components: This contains special regions such as the header and footer that will probably be only used once per page. sections: This will contain reusable, self-contained sections mostly based on the Repeater Matrix types. They may be used multiple times on one page. pages: High-level templates corresponding to ProcessWire templates. Those contain very little markup, but mostly include the appropriate components and sections. Depending on the size of the project, you could increase or decrease the granularity of this as needed, for example by grouping the sections into different subfolders. But it's a solid start for most medium-sized projects I tackle.
      Anyway, thanks for reading! I'll post the next part in a couple of days, where I will go over how to add more functionality into your environment in a scalable and reusable way. In the meantime, let me know how you would improve this setup!
    • By MateThemes
      Hello everyone!
      I have a markup and image field question:
      I have a markup in which a gallery preview should be displayed on home page. This gallery have a special markup, 3 of 4 images have special image ratio.

      The gallery looks like this. 
      The html markup is like this:
      <div class="uk-section-muted" uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-slide-top-small; delay: 200;"> <div data-src="./assets/images/arrahof/home-restaurant-bg.svg" class="uk-background-norepeat uk-background-contain uk-background-top-center uk-section uk-section-large" uk-img> <div class="uk-container uk-container-small"> <div class="uk-margin-large" uk-grid> <div class="uk-width-1-1@m"> <h2 class="uk-text-center" uk-scrollspy-class>Das Angebot im ArraHof</h2> </div> </div> <div class="uk-grid-small uk-grid-margin-small" uk-grid> <div class="uk-width-expand@s"> <div class="uk-margin-remove-vertical uk-text-center" uk-scrollspy-class> <a class="el-container uk-inline-clip uk-transition-toggle uk-link-reset" href="#"> <img class="el-image" data-src="https://via.placeholder.com/610x604" data-sizes="(min-width: 610px) 610px" data-width="610" data-height="604" alt="Placeholder Image" uk-img> <div class="uk-overlay-default uk-transition-fade uk-position-cover"></div> <div class="uk-position-center uk-position-small"> <div class="uk-overlay uk-padding-large uk-transition-fade uk-margin-remove-first-child"> <h3 class="el-title uk-h4 uk-heading-divider uk-transition-slide-top-small uk-margin-top uk-margin-remove-bottom">Lorem Ipsum</h3> <div class="el-content uk-panel uk-transition-slide-bottom-small uk-margin-top">Comfort Food</div> </div> </div> </a> </div> </div> <div class="uk-width-expand@s"> <div class="uk-margin-remove-vertical uk-text-center" uk-scrollspy-class> <a class="el-container uk-inline-clip uk-transition-toggle uk-link-reset" href="#"> <img class="el-image" data-src="https://via.placeholder.com/610x604" data-sizes="(min-width: 610px) 610px" data-width="610" data-height="604" alt="Placeholder Image" uk-img> <div class="uk-overlay-default uk-transition-fade uk-position-cover"></div> <div class="uk-position-center uk-position-small"> <div class="uk-overlay uk-transition-fade uk-margin-remove-first-child"> <h3 class="el-title uk-h4 uk-heading-divider uk-transition-slide-top-small uk-margin-top uk-margin-remove-bottom">The Williams family</h3> <div class="el-content uk-panel uk-transition-slide-bottom-small uk-margin-top">Comfort Food</div> </div> </div> </a> </div> </div> </div> <div class="uk-grid-small uk-grid-margin-small" uk-grid uk-height-match="target: .uk-card; row: false"> <div class="uk-width-2-3@s"> <div class="uk-margin-remove-vertical uk-text-center" uk-scrollspy-class> <a class="el-container uk-inline-clip uk-transition-toggle uk-link-reset" href="#"> <img class="el-image" data-src="https://via.placeholder.com/610x400" data-width="610" data-height="400" alt="Placeholder Image" uk-img> <div class="uk-overlay-default uk-transition-fade uk-position-cover"></div> <div class="uk-position-center uk-position-small"> <div class="uk-overlay uk-transition-fade uk-margin-remove-first-child"> <h3 class="el-title uk-h4 uk-heading-divider uk-transition-slide-top-small uk-margin-top uk-margin-remove-bottom">The Williams family</h3> <div class="el-content uk-panel uk-transition-slide-bottom-small uk-margin-top">Comfort Food</div> </div> </div> </div> </a> </div> <div class="uk-width-expand@s"> <div class="uk-margin-remove-vertical uk-text-center" uk-scrollspy-class> <a class="el-container uk-inline-clip uk-transition-toggle uk-link-reset" href="#"> <img class="el-image" data-src="https://via.placeholder.com/610x820" data-sizes="(min-width: 610px) 610px" data-width="610" data-height="820" alt="Placeholder Image" uk-img> <div class="uk-overlay-default uk-transition-fade uk-position-cover"></div> <div class="uk-position-center uk-position-small"> <div class="uk-overlay uk-transition-fade uk-margin-remove-first-child"> <h3 class="el-title uk-h4 uk-heading-divider uk-transition-slide-top-small uk-margin-top uk-margin-remove-bottom">The Williams family</h3> <div class="el-content uk-panel uk-transition-slide-bottom-small uk-margin-top">Comfort Food</div> </div> </div> </div> </a> </div> </div> </div> <div class="uk-margin-large" uk-grid> <div class="uk-width-1-1@m"> <div class="uk-text-lead uk-width-xxlarge uk-margin-auto uk-text-center" uk-scrollspy-class>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur.</div> <div class="uk-margin-medium uk-text-center" uk-scrollspy-class> <a class="el-content uk-button uk-button-default uk-button-large" href="#">Unterkunft</a> </div> </div> </div> </div> </div> How can I achieve when I have an image field to add the custom markup within the image field? I have no clue to get this done.
      Thank you!
    • By Robin S
      This module is inspired by and similar to the Template Stubs module. The author of that module has not been active in the PW community for several years now and parts of the code for that module didn't make sense to me, so I decided to create my own module. Auto Template Stubs has only been tested with PhpStorm because that is the IDE that I use.
      Auto Template Stubs
      Automatically creates stub files for templates when fields or fieldgroups are saved.
      Stub files are useful if you are using an IDE (e.g. PhpStorm) that provides code assistance - the stub files let the IDE know what fields exist in each template and what data type each field returns. Depending on your IDE's features you get benefits such as code completion for field names as you type, type inference, inspection, documentation, etc.
      Installation
      Install the Auto Template Stubs module.
      Configuration
      You can change the class name prefix setting in the module config if you like. It's good to use a class name prefix because it reduces the chance that the class name will clash with an existing class name.
      The directory path used to store the stub files is configurable.
      There is a checkbox to manually trigger the regeneration of all stub files if needed.
      Usage
      Add a line near the top of each of your template files to tell your IDE what stub class name to associate with the $page variable within the template file. For example, with the default class name prefix you would add the following line at the top of the home.php template file:
      /** @var tpl_home $page */ Now enjoy code completion, etc, in your IDE.

      Adding data types for non-core Fieldtype modules
      The module includes the data types returned by all the core Fieldtype modules. If you want to add data types returned by one or more non-core Fieldtype modules then you can hook the AutoTemplateStubs::getReturnTypes() method. For example, in /site/ready.php:
      // Add data types for some non-core Fieldtype modules $wire->addHookAfter('AutoTemplateStubs::getReturnTypes', function(HookEvent $event) { $extra_types = [ 'FieldtypeDecimal' => 'string', 'FieldtypeLeafletMapMarker' => 'LeafletMapMarker', 'FieldtypeRepeaterMatrix' => 'RepeaterMatrixPageArray', 'FieldtypeTable' => 'TableRows', ]; $event->return = $event->return + $extra_types; }); Credits
      Inspired by and much credit to the Template Stubs module by mindplay.dk.
       
      https://github.com/Toutouwai/AutoTemplateStubs
      https://modules.processwire.com/modules/auto-template-stubs/
    • By abdulqayyum
      Hy Processwire community,
      There are some problem in fileCompiler cache.
      when i change under the directory \site\templates\ it must change under the directory /site/assets/cache/FileCompiler/site/templates/
      but it does not update and functionality working with /site/assets/cache/FileCompiler/site/templates/ directory.
       
      In this case please suggest me how i clear fileCompiler cache?
      what i have to clear it manually?
      Thanks AbdulQayyum.
×
×
  • Create New...