Jump to content

Creating dynamic blocks on a per page basis


nickngqs
 Share

Recommended Posts

Hi guys,

I'm trying to wrap my head around creating dynamic blocks where the end-user can add blocks on the fly on individual pages without specifying it in the templates.

What approach do you guys usually do? I've tried scouring the forum for solutions but seems to get abit confusing. I've read Hanna Code, Repeater Matrix, PagesTables and seen the youtube tutorials. Not sure, where to start from. I only got very minimal knowledge of php as I came from a front-end background (html, css, js)

I'm looking to define my blocks somewhere where the end-user will not be able to see.

For example, a simple block container

<div class='container'>
<div class='container__title'> {{ $title-field }} </div>
<div class='container__image'> {{ $image-field }} </div>
</div>


Then maybe we got a second block container

<div class='container-2'>
<div class='container-2__title'> {{ $title-field }} </div>
<div class='container-2__image'> {{ $image-field }} </div>
</div>


Then the end-user can just to add these blocks into any pages on the fly and re order them according to their needs. My processwire is v3 using the UIKit3 Admin if that makes any difference

Sorry if I sounded too noob.

Link to comment
Share on other sites

1 hour ago, abdus said:

Thanks @abdus for those links, I didn't knew they exist!

Good articles @Michael van Laar, please keep going on the series!

  • Like 1
Link to comment
Share on other sites

This is something that I've been trying to figure out for quite awhile. At the moment I do this:

1) Create template banner-index
2) Create template banner-entry
3) Create page 'Banners' using banner-index template
4) Create child page of whatever the banner will be, let's say 'Sounds good'.

So you now have:

1.png.e6f1c7b6cece178a5d694ca818652cc9.png

... and the template for 'Sounds good':

2.thumb.png.df3322e0599d99776481759ab02efc44.png

(link to page is a Page type which enables me to pick ANY page on the site with a PageListSelect+ as input field type and 'Home' set as parent)

So I create a file which is going to output the actual banner:

// includes/_banner.php
<?php namespace ProcessWire;
    // get the banner page determined by the id passed to this template
    // from wireIncludeFile additional array, see next snippet
    $banner = $pages->get($Id);
?>

<div class="jumbotron jumbotron-fluid py-6 text-center bg-repeat">
    <div class="container">
        <h2 class="display-4"><?= $banner->headingMain; ?></h2>
        <p class="lead"><?= $banner->headingSubtitle; ?></p>
        <a href='<?= $banner->linkToInternalPage->url; ?>' class='btn btn-primary'>Go to <?= $banner->linkToInternalPage->title; ?></a>
    </div>
</div>

...then I grab this file using 'wireIncludeFile' so I can pass an additional value into this template which is the id of the page:

// views/about.php
<?php wireIncludeFile('./includes/_banner', array('Id' => 1212)); ?>

So the page id of 'Sounds good' is '1212'. I pass this manually at the moment.

So now, when /about/ is viewed, it displays '_banner.php' wherever I want, where you can see the PHP is populated with values from the 'Sounds good' page:

3.thumb.png.7cb8b0686ac47feab5f7f969e504b241.png

So, what about making this a bit more dynamic instead of manual IDs in a template.

Create a new field 'bannerToDisplay' as a 'Page' field type:

4.thumb.png.a7d9e25e096889c1faef06a268340704.png

...then select it to return just a single page:

5.thumb.png.88dc472f136bef5f27140759dafcf604.png

...and choose the parent of selectable pages to be the 'Banners' page you made earlier using the 'banners-index' template with an input field type of 'Select':

6.thumb.png.5199b614caee70a7110ddf828a8fe77c.png

...go add this bad boy to a template!

7.thumb.png.e5361c0cc45f1608e601554201a4cb6b.png

...then go edit your page:

8.thumb.png.978155967e7f69b380b0a240deb8ef44.png

...choose a banner, save it. Go edit the code which renders '_banners.php' and get rid of that manual ID:

// views/about.php
<?php
     // if something has been selected from the 'Choose a banner' dropdown
    if ($page->bannerToDisplay) {
        // get the ID of the selected page
        $bannerPageId = $page->bannerToDisplay->id;
        // pass this ID to the _banner.php template
        wireIncludeFile('./includes/_banner', array('Id' => $bannerPageId));
    }
?>

...create another banner and then change the dropdown and refresh the page!

10.thumb.png.0031b8c14d1ac7a561f726f303f99df7.png

This is obviously just an example which enables adding of a single block but once you get the idea of the Page field type and how you could use it, your options will increase a fair bit.

The thing I found with repeaters is that you still can't add a content block above, say , a body field, then another one below it. Your template would literally just have to have the repeater on it and you add item after item. Of course, with a repeater, every item will be the same (defined once, then just repeated with alternative content in the same field types).

I'm going to try the pro fields repeater matrix next for something similar. I'd love to be able to make entire pages simply from blocks and to be able to drag them around. It takes a fair bit of forethought though. Just experiment, have fun!

NOTE: This still means you have to define WHERE the banner will go on the page via a template, but you can change WHICH banner to display on the page edit inside admin :) it doesn't solve your problem but hopefully helps a bit and gets you on your way. Good luck!

  • Like 3
Link to comment
Share on other sites

I have used Repeater Matrix for this purpose, to create a type of page builder, each repeater type being a possible section, though you still have to have a predefined set of repeater types, most of this types have a checkbox or two for customization of behaviour (even repeaters inside, works wonderful)

 59a7245f9d7f9_ScreenShot2017-08-30at3_46_23PM.thumb.png.3d4e93313940830ce8cea987891a4f37.png

 

  • Like 3
Link to comment
Share on other sites

21 minutes ago, elabx said:

I have used Repeater Matrix for this purpose, to create a type of page builder, each repeater type being a possible section, though you still have to have a predefined set of repeater types, most of this types have a checkbox or two for customization of behaviour (even repeaters inside, works wonderful)

 59a7245f9d7f9_ScreenShot2017-08-30at3_46_23PM.thumb.png.3d4e93313940830ce8cea987891a4f37.png

 

Nice. I like this approach, I tried similar but failed a while back, just couldn't get the desired HTML output. Will give it another shot with repeater matrix.

Link to comment
Share on other sites

  • 4 months later...

@louisstephens  Those content sections are just rendered with a foreach loop like:

foreach($page->test_matrix as $item) {
  if($item->type == 'blockquote') {
    echo "
      <blockquote>
         <p>$item->quote</p>
         <cite>$item->quote_cite</cite>
      </blockquote>
      ";
  } else if($item->type == 'bodycopy') {
    echo "
      <h2>$item->title</h2>
      $item->body
      ";
  } else if($item->type == 'gallery') {
    // and so on...
  }
}

That code was taken from http://processwire.com/api/modules/profields/repeater-matrix/

So when a user changes the order, it will automatically be displayed in that order on the frontend.

  • Like 1
Link to comment
Share on other sites

17 hours ago, louisstephens said:

@elabx, I know this is an older post (by a couple months), but how to you set up your template to handle if a user moves a section around (ie, moves the feature card above the intro)? 

Just to give another opinion from @gmclelland , I organize the templates the following way:

site/templates/fields/{name of the repeater matrix field}/{name of the rep. matrix type}

e.g.

Assuming a repeater matrix field called "content" with a type called "slider":

site/templates/fields/content/slider.php

So I rather end up with several files instead of rendering in the main template, one per matrix type. Then, on the template which has the repeater matrix field:

content$page->render("content")

 

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

Hey there. I am facing a similar challenge now when building my new profile and reached to a level where I would have the following markup blocks: 3 header types, 7 slider types, over a dozen of content presentation blocks. To come up with a plan, I decided to first draw it on paper and then think of how other platforms are building the admin pages. So it appeared to me, that I could use the core functionality of PW and just setup a few fields that would be holding the choices for Header, Main, Sidebar, Footer etc. To make them appear clearly, I set the header field width 100%, the main to 70% and the sidebar to 30%. The footer is also 100% as per the markup, but the values can be changed). So I added the fields as Select Option type and set the header as single value and all the other as ASM Select (multiple values). Added the files for all my types with a name and number (eg. header-1.php, main-slider-1.php, sidebar-widget-1.php etc.) and then I would include the selected choice using the selected option ID (all the choices are listed in the details tab-selectable options). Because of the ASM Select, all my blocks would be movable and I can change the order, repeat one or remove easily. I've already used a similar structure in another project and it worked like a charm, however I must say that it does not look very good when the header is set to 100% width but the content of it is using only about 30%... I am thinking now that I can even use a more descriptive name of the files like top-news-tabs.php and still call them with a simple case {...} php function just because every option would have an ID assigned to it so it won't matter the file name. However, if I manage to achieve that, it would be much more descriptive partials file is doing what and if I have to revise the project later or hand it over to another user, it would be easier to get straight to the point.

I am welcoming any other ideas or tips how to better style the template parts as the only extra way I can think of is to use fieldset open for every part which would make it a bit more eye appealing but would cost me a few extra fields again for open/close ?

Link to comment
Share on other sites

After some playing around, I was able to come with some basic (not fully completed yet) structure of my page builder:

Site-layout.thumb.jpg.58cc71191398b6772827b9e6b6a61b23.jpg

To be honest, I could have lived with this approach, however (it turns to a habit for me these days ? ) there is one tiny issue with it - ASMSelect ONLY allows me to add one instance of every block, after which the choice is grayed out. If by any chance the idea is to have only one occurrence of the block and to just drag them to order, than it would need some extra polishing and will be good to go. However I am aiming at allowing multiple occurrences of a block and besides that I would need to pass some options in order to have different pages listed from the same block (category id/name, number of pages in the list etc.). In such case, I might be better of using a repeater and creating some pages for every block and widget. And for the options I will use some conditional fields.

Unless, of course, someone has a better idea of an approach that is easier, more elegant and allows once defined blocks to be added through the different sections.

Link to comment
Share on other sites

Hello again all. I've been having fun to change the approach and the repeater works great now. If I have the zones predefined (as it is shown on the image of my earlier post), the repeater allows me to add as many blocks/widgets as I want as well as to order them. However, as far as I've built the markup to have a middle section that would be 100% width of the page, I started thinking how can I allow the middle section to be moved up, down etc. In other words, to be closer to a dynamic builder as it appears with WordPress or else, but with the OOB PW utilities and API. Then I got this crazy idea, that I can add a field in the repeater that would allow me to add some custom markup, where that could be an opening div, closing div etc. So if my logic is OK, I will be able to start building my blocks with some custom markup (opening divs for main section, then select some blocks, then add the closing section etc.) If I decide, I should be able to move up the middle section (100% width) etc. As an idea it sounds great, but I will have to test it to see how would that work and if successful - will share some more details.

Oh, and I have one more idea to test which involves the use of Hanna Code module where instead of files I would define all my widgets and blocks in the module and then just call them when needed. I am not sure would that slow down a bit the site loading, but my guess is that if caching kicks in properly, most of the pages would load from the cache, so should not be much impact. On the other side though, I will be able to edit the code straight from the PW Admin and there will be no need of file editing ? But first I will start with the files to test the concept and if that works fine, would move to the next level and see how it goes.

Link to comment
Share on other sites

After a few tests today with a repeater field, I found that for the proper markup I would need to create quite a few new fields that would hold the necessary variables for the widgets and blocks. On the other hand, if I use Hanna Code module, I would be able to pass to the scripts some variables like (category, page list limit etc.) so that would allow me to easily include the same block listing different categories and so forth by just modifying the parameters of the Hanna Code tag. Besides that, with the help of HannaCodeDialog I might actually add the blocks to the CKEditor, so that could turn to be a game changer ? Let's not forget the fact that I won't need to edit any files manually other than just applying any needed changes straight to module ? To tighten up the security, I would allow the module to be used by Super Users only.

P.S. After embracing the HC idea, I realized that once I define the needed blocks of code, I could easily export them and re-purpose them for any other projects needing similar functionality. If anyone knows of some downsides of using HC and suggestions to avoid them, it would be great!

Link to comment
Share on other sites

Thanks @gmclelland You gave me a reading to have fun with. Thank you for the compiled list, I might change the approach - you never know. So far I really liked the HC as it gave me some portability to reuse the tags code from project to project and I am starting to think whether I should add some BS4/UIKIT tags that would allow me to quickly build blocks. I won't rush it yet before reading the file you shared.

 

Link to comment
Share on other sites

On 4/24/2019 at 12:46 PM, MilenKo said:

Thanks @gmclelland You gave me a reading to have fun with. Thank you for the compiled list, I might change the approach - you never know. So far I really liked the HC as it gave me some portability to reuse the tags code from project to project and I am starting to think whether I should add some BS4/UIKIT tags that would allow me to quickly build blocks. I won't rush it yet before reading the file you shared.

 

For small websites, I have used top-level pages as pages, and use child pages as content rows.  For larger ones I use the normal pages as pages that can have child pages, and make a Settings page that holds sitewide settings, with theme children, and layouts as children of the theme.  I can assign a design row or php code snippet to a page, template, or make it sitewide.  You can see some details on my forum post. 

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

@joer80 I've seen your masterpiece in the showcases. It is a cool thing you've built ? With me - I am thinking more simply - where I would try to build a dozen of Hanna Code blocks with all the buzz and fuss in it and then have the "builder" contain some sections of the website where you could insert your HC tags. At least that is what I am experimenting with presently while building a pretty complex content page with several blocks and options to set. I've completed the initial functionality but I still have a few more blocks to build and I will be able to share a little demo of the concept.
 

Link to comment
Share on other sites

On 1/11/2018 at 11:25 PM, gmclelland said:

foreach($page->test_matrix as $item) { if($item->type == 'blockquote') { echo " <blockquote> <p>$item->quote</p> <cite>$item->quote_cite</cite> </blockquote> "; } else if($item->type == 'bodycopy') { echo " <h2>$item->title</h2> $item->body "; } else if($item->type == 'gallery') { // and so on... } }

For this purpose, a switch-statement would be a bit more readable and faster. If there are more than 3 conditions to check (one var with different values), you should use switch. Switch is also slightly faster, because it just computes the condition once and then checks for the output while if / elseif / else has to be computed every time.

Link to comment
Share on other sites

  • 2 weeks later...

I was looking today at the PRO FIELDS MODULE and it seems to be the perfect fit in many occasions to complete a very easy to administer page builder, however that would require some investment to make. Quite honestly, if anyone is determined to use ProcessWire as a developer, the module cost would worth every penny and if I understood correctly, it would allow an unlimited number of websites to be used on. This is like a developers edition for Process Cache etc. I guess I will complete my profile using standard fields in combination with Hanna Code and Hanna Dialogue (using some attributes for selectors) but later on I will switch to PRO once I get the finance sorted out ? Presently I've almost completted the blocks structuring so it is just a matter of time and efforts to build the blocks for every section and move on. Will post some screenshots/info once ready.

  • Like 1
Link to comment
Share on other sites

So after playing a bit here and there, I came up with a simple structure that would hold the following blocks:

Header style, Slider style, upper/middle/lower main section, upper/lower sidebar section and a footer one.

One of the header styles markups allows for a header banner so I set the field with Select options and added a condition when to show the code field that would hold the banner (header_style=1).
The slider has been set the same way with six different styles using Select option but the seventh option allows for no slider at all.

For the main area blocks, I will be using Hanna Code in combination with Dialogue where I have some attributes for different blocks representation (category, number of posts, field descriptions/notes etc.). This allows the blocks to be re-organized in a preferred way as well as to repeat or swap blocks from zone to zone. The main block and sidebar are split by a full-width section where I can add a large banner and any other larger blocks to present some content.

For the footer - nothing much to say - the same approach as for the main area.

Sidebar - same thing as the footer and main area - HC & Dialogue.

 

Spoiler

Simple-page-blocks-processwire.thumb.png.b1c8dd43f292f95263ec040d93e363c8.png

Like I said, nothing special here, but it is easy to configure and modify if a need be.

Link to comment
Share on other sites

I had an edit button that edits the page you are on, but I am playing with just making it highlight all of the sections on the page and make an edit button for that section.  See this video. 

I dont like how it doesnt give you live preview though, so I am playing with vue to do this.

 

  • Like 1
Link to comment
Share on other sites

Nice work joer80. Looks great. I am wondering though, how many fields would you count in your profile as only the Tab_open takes two per section so unless you use some tricks, you might end up with a huge fields list?

Btw, after completting my two category blocks with all the bells and wistles I realized that instead of using one tab_category attribute and set its type to asmselect I used 10 fields (tab_category_1, 2, etc.) which caused me some troubles to check the array for empty values, then sort them out etc. I am working on redoing the markup which would simplify a lot the code and would be much easier to "digest" and re-purpose. 

ProcessWire keeps amazing me every single day with the freedom of code, approaches, functionality OOB etc. It really applies to the saying: Sky is the limit! 

  • Like 1
Link to comment
Share on other sites

No, I create generic fields.  Things like single_line_text1, single_line_text2, checkbox1, checkbox2, richtext1, richtext2.  Then any page that needs one just pulls one in. 

The tabs I use are usually Content, Design, and Advanced.  

Not many fields at all.

Link to comment
Share on other sites

I see, but at your admin on the video in Design tab you have over 15 fields not counting Fieldset in tab (open/close) (for the design) and Fieldset (open/close) for Basic, Text align, margin, padding. It is a similar scenario with me and that is why I am trying to reduce the number of fields. I know with ProFields I could reduce them a lot, but not yet there financially.

Link to comment
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
 Share

×
×
  • Create New...