Jump to content

Simple widgets logic

Recommended Posts

Hey everyone. I am at a stage of code cleaning for my first PW profile where I decided to implement some sidebar widget logic that would allow me to remove code repetition. I read about a few widget logic approaches that were working fine but that seemed too complicated for my needs so decided to implement something really simple that would do just that - widget logic that can be changed through the admin but not through code editing.

So before I share my idea, I would give you some info of the structures I have:

-- Recipes
---- Child 1
---- Child 2
-- Ingredients
---- Child 1
---- Child 2

So in my project needs, I wanted to have a solution that would allow me to set through the profile admin one or group of widgets per template (it would allow unlimited widgets as far as I have the code for it).

So to achieve this functionality, I took the following steps:

1. Create a template, called widget_logic and set the allowed template for children to be itself (widget_logic)
2. Create a page Site Widgets and assign to it the widget_logic template.
3. Create a field called listing_widgets and set its type to Page Reference.
4. In Details tab select Multiple Page Array to allow multiple widgets to be selected.
5. In the input tab chose Page Auto Complete as input field type.
6. In Selectable pages point the parent to your widgets page name (Site Widgets in this example) and set the widgets_logic as the template.
7. Repeat the steps 3-6 creating another field: inner_widgets (this would allow you to have different widgets per listing template and inner page ;) )
7. Add manually the child pages with the widgets names in Site Widgets page you just created.
8. Assign the fields to the parent templates that you want the widgets to be pulled from (in this case: Recipes, Blog etc.)
9. In the template code, pull the page parent through API using the loop you use to list the results in the page. For this tutorial I will set the widgets to Recipes template that shows a listing of all the recipes matching my criterias:

//Build a selector and limit page results to 5
$result = $page->children("limit=5, sort=-published");

//Pull the parent of the first child-page to be used for widget logic
$parent = $result->first()->parent();

10. Once we know the parent and we know the field names assigned to it containing the widgets, we use a simple loop in each template to get the selected widgets name and include them where needed. Note, for the widgets naming I used: widget-XXX-YYY.php (eg. widget-recipe-top.php). If you prefer other naming, make sure you change the include line to match the new names.

//Loop through all the widgets setup in the parent template
foreach ($parent->listing_widgets as $w) {    

//Including all the widgets by file name and order set in the parent widgets field    
include ('./includes/widget-' . $w->title . '.php');

11. In the Recipe-inner template I would do the same:

$parent = $page->parent();
//Loop through all the widgets setup in the parent template
foreach ($parent->inner_widgets as $w) {    

//Including all the widgets by file name and order set in the parent widgets field    
include ('./includes/widget-' . $w->title . '.php');

NOTE: in the inner page template I changed the field name to inner_widgets to pull the widgets for the inner page.

12. Now all that is left is to assign the two fields to every parent and/or inner page template that you would like to use the simple widget logic and select the widgets for each one.

It might not be the best approach, however it is super simple to setup and allows me to have different widgets on any template now. The variety of widgets could be extended at any time by just adding the new widget, create the page with the name for it and assign it to the chosen template. Having the Page Auto Select field would allow you to drag and drop the widgets to reorder them so it suited my needs perfectly. Hope it would for you as well. Any code improvements are more than welcome (as usual ;)

P.S. On the image of widgets view, I set the size of both fields to be 50% so that they show up on the same line and save the space and scrolling.


  • Like 6

Share this post

Link to post
Share on other sites

I am starting to think that this approach can be used to widget-ize a profile completely if the widget names are descriptive and their code inserted in the right spot. I have had a theme for WordPress where initially there was nothing on the main page but a bunch of widgets and a big list of widget areas to insert them. Sky is the limit, but some more extent might be needed for the things to work perfectly ;) Will try to take the approach on next project and see how it goes...

Share this post

Link to post
Share on other sites

After rethinking the Simple Widget Logic mechanism, I decided to try to unify the sidebar code, so that it can be included on every template where a need is. To make it work for all my listing and inner view templates, I needed to add some more logic to it. So here are the extra steps I took to make it happen:

1. All page listing template selectors variable was made identical (in the example bellow I am showing the change for Recipes parent template):


//Build a selector and limit page results to 5
$recipes_list = $page->children("limit=5, sort=-created");


//$list variable would be used for every parent template to unify the sidebar query
$list = $page->children("limit=4, sort=-created");

2. Removed the $parent selector from every template.

3. Changed the variable in the page rendering code from $recipes_list to $list.

4. Copied the code for the sidebar and put it in a separate file, called _sidebar.php in the main template folder. In the sidebar I had the logic now:

<div class="col-md-4 col-lg-3">
		<div class="side-bar">											
			//Check if the present page has children
			if($page->hasChildren()) {
				//Grab the parent from $list and set the widgets source to listing_widgets field
				$widgets = $list->first()->parent()->listing_widgets;
			} else {
				//If the page is a child, grab the parent and set the widgets source to inner_widgets field
				$widgets = $page->parent()->inner_widgets;
			//Loop through all the widgets setup in the parent template
			foreach ($widgets as $w) {	

			//Including all the widgets by file name and order set in the parent widgets field	
			include ('./includes/widget-' . $w->title . '.php');
		} ?>														

5. Included the _sidebar.php in every template (listing and inner):

<!-- Sidebar -->
<?php include ('./_sidebar.php') ?>
<!-- Sidebar -->


And voila, now the sidebar markup is unified and depending on which template is rendered the $parent is pulling its name and then all the widgets selected in the parent field are applied.

An improvement would be to make the system work with a delayed output, but I am not yet there. Hopefully I will switch to it in my profile v. 2 :)

Note: There is only one issue I see with this approach - if I decide to move the _sidebar.php to the include folder where all the widgets resign, changing the path of the widgets to:

include ('./widget-' . $w->title . '.php');

works only for the parent template, but not for the children. While browsing the children pages, it shows that the widgets path is not found. That is why I had to move the _sidebar.php to the main templates folder so that the path is working for both. Maybe someone knows a way to have that fixed so that I could move the sidebar file back to /includes/ folder?

Share this post

Link to post
Share on other sites

Guys, I just edited the sidebar code as I noticed that both templates (listing and inner) were pulling the widgets from listing one only. Besides that I removed the $parent variable and inserted its value in the $widgets that now holds the proper query to listing or inner depending on the fact if the page is the parent or a child. Now it is working fine and the code got a bit shorter ;)

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 ridgedale
      Reference: PW 3.0.62 and uikit3 based site using the Reglar-Master profile.
      I'm trying to add a count of the number of category posts to display beside each of the category titles listed in the sidebar on the blog page.
      The following code displays the total number posts on each category page:
      <span class='uk-text-muted'>Total <?php echo page()->title; ?> posts: <?php echo count(pages()->get('/blog/')->children("categories=$page")); ?></span> The following default code displays the heading and a list of the categories:
      <?php $categories = pages()->get('/categories/'); echo ukNav($categories->children, [ 'header' => $categories->title ]); ?> but I want to add the respective number of posts on the same line as each category title listed. When I try replacing the default code with the following:
      <?php $categories = pages()->get('/categories/'); $catposts = count($categories->children("categories=$page")); echo ukNav($categories->children . ' ' . $catposts, [ 'header' => $categories->title ]); ?> I get the following error:
      which refers to the following code in the _uikit.php file:
      $page = $items->wire('page'); // current page and when I try:
      <?php $categories = pages()->get('/categories/'); $catposts = count($categories->children("categories=$page")); echo ukNav($categories->title); foreach ($categories as $category) { echo $category->children . ' ' . $catposts; } ?> or:
      <?php $categories = pages()->get('/categories/'); $catposts = count(pages()->get('/blog/')->children("categories=$page")); echo ukNav($categories->title); foreach ($categories as $category) { echo $category->children . ' ' . $catposts; } ?> I get the same error.
      If I change
      I get the following error messages:
      Any advice on where I am going wrong would be very much appreciated.
    • By MilenKo
      Hello guys. I am super happy to be passing to the final cleanup of my first custom build theme and to start applying the SEO optimization modules/code. I noticed something strange this morning and can't find out where exactly is my issue. Hopefully it is a quick fix or silly miss on my side.
      So here is the issue: I am generating a list of all my recipes in the db using the following query:
      <?php if($page->numChildren) { //Build a selector and limit page results to 10 $recipe_results = $page->children("limit=4"); //Assign results of the array to $listing foreach($recipe_results as $index => $listing) { //Limit the text content to 160 chars using the function in function.php $text = $sanitizer->textarea(truncate("$listing->recipe_intro_text", 160)); ?> Then follows the boring part of html insert of the variables, clases etc. The listing works fine. So as far as there would be more than the planned results per page, I implemented the page rendering using the following code:
      <!-- Pagination --> <?php echo $recipe_results->renderPager(array( //Show font awesome right hand icon for next page 'nextItemLabel' => __("<i class='fa fa-hand-o-right'></i>"), //Show font awesome left hand icon for previous page 'previousItemLabel' => __("<i class='fa fa-hand-o-left'></i>"), //Define the active class of current page 'currentItemClass' => "current", //Define the block markup code 'listMarkup' => "<ul class='page-nav'>{out}</ul>", //Define the item markup code and applying currentItemClass 'itemMarkup' => "<li class='{class}'>{out}</li>", //Generating the link appearance of all buttons 'linkMarkup' => "<a href='{url}'>{out}</a>", )); ?> <!-- Pagination --> And again, everything worked perfectly after I allowed page numbers. 
      So then I implemented a few similar queries in the sidebar of my website, listing content from other page parents/children. Here is one example:
      <?php $favorite_books = $pages->find("template=books-inner, sort=-random, limit=3"); foreach($favorite_books as $b) { if (count($b->book_images)) { $thumb = $b->book_images->first->size(70,60)->url; $desc = $b->book_images->first->description; } else { $thumb = $settings->small_thumb->url; $desc = "NoThumb"; } ?> <li> <div class="thumb"> <a href="<?php echo $b->url?>"> <img src="<?php echo $thumb?>" alt="<?php echo $desc?>"/> </a> </div> <div class="detail"> <a href="<?php echo $b->url?>"><?php echo $b->title?></a> </div> </li> <?php } ?>  
      It was all working fine, until I started browsing page 2, 3, etc. It appears for some reason, that the pageRendering is applied not only to $recipe_results, but also to all requests from the widgets. So on page 1, I get the proper number of recipes and proper number of results in the widgets (books in this example). If I browse to page two, I still see the proper recipes number and everything else, but the widgets show only 1 result (as far as I have imported 4 test posts only). On page 3, it shows notihing in the widgets, but recipes are OK again.
      As far as to render pages I am using $recipe_results and the pageRender is called for that variable, I am not sure why it is also applied to $favorite_books and other widgets. Any suggestions or ideas what is going on? I tried to change every variable on the page thinking that I might be having a call to the same one, but it is obvious in the example that they do not match...
    • By ridgedale
      I need to separate the header, footer and sidebar from the _main.php file.
      I've tried all of the following without success:
      <?php include ("header.php"); ?> <?php include ("/_header.php"); ?> <?php include ("./header.inc"); ?> <?php $header = pages()->get('/rcl-header.php'); // include header echo $header; ?> Any guidance would be appreciated.
    • By franciccio-ITALIANO
      Hello, I installed processwire and create 10 pages.
      But when I open it, the fields "Body" and "Sidebar" are empty, all blank. I can't write anything!!
      Must I activate anything or I must repeat the installation?

    • By berechar
      Hi all,
      A question regarding security/best-practice concerning a simple front-end login through AJAX calls. My plan is to use this kind of module inside a small AngularJS architecture to update the entire application when someone is logged in/out.
      I've made a simple HTML form in which the user can login by typing his/her username and password in the corresponding fields. After submitting the form, these values are fetched with jQuery. Then an Ajax GET request is made with these values to a page which has access to the Processwire API. This page checks if these values (after sanitization) correspond to an existing user in the CMS.
      If the user and password matches, the user is logged in, and a success message is being returned.
      If the user and password mismatches, an error message is being returned.
      I don't know much about encryption, therefore I highly doubt if this a 'safe' way of doing things. Hopefully someone can give me some pointers on this!
  • Create New...