Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 09/30/2022 in all areas

  1. This week I've been working on something a little different: developing a new site profile in ProcessWire. Actually, I should probably call it an application profile rather than a site profile, as it's not a website profile. Instead it's a profile for an invoicing application in ProcessWire. Though you would install and run it on a web server, but it would be an independent application rather than part of a website... perhaps something you run in a subdirectory, subdomain, or even localhost. This is something I've been wanting to build for awhile—ever since the invoice service I use raised their rates beyond my budget. So I thought I'd build a replacement that I could use, as well as share for others that might have a similar need. I think it might also be a pretty decent PW profile example in general, too. I'd originally considered building it as a Process module but decided not to for a few reasons. Though the biggest one is that a site profile enables the greatest potential for customization and expansion according to each person's needs. Since you can expand upon it by adding your own fields and templates, or editing existing ones, most can really tailor it to their own needs a lot more easily than they could if it were a Process module. Likewise, since the actual invoices (and invoice emails) are rendered from front-end pages, you can customize the look and feel of them to match your brand very easily. (This is something I always wished I could do with the invoice service I've been using previously) This invoice profile requires nothing other than the ProcessWire core. It has no 3rd party or Pro module dependencies. I've got it largely functional at this stage, though will be putting a couple more weeks work into it before releasing it. I'd like to build in the option for clients to pay an invoice with a credit card (via Stripe) for instance. Below are a few screenshots of the work in progress. First is the page-list which shows the current invoices in the system and their status. (click image to view larger) As you can see, there are also pages for Clients and Settings. The client pages contain all the information about each client that invoices can be created for. The Settings page is where you can edit your own company information, logo and billing preferences. Next is the invoice editor. Here we have a repeater for each line item in the invoice. We also have a repeater for payments. All of the totals add up automatically as you type (Javascript added via hooks). They are also calculated automatically at the server side, so that everything stays consistent whether working with the API or in the page editor. (click image to view larger) At the bottom of the invoice editor you'll see a collapsed input for "Invoice action". This is where you can select actions to apply to the invoice. The two we currently have are "Email invoice to client" and "Email invoice to another address". Next up is what we see when viewing the invoice on the front-end. This is just the output of a template file but it is optimized for printing, saving to PDF and sending through email. I've kept it intentionally simple but of course the logo would be replaced with your own and all markup/styles are fully under your control. (click image to view larger) What I plan to add next are payment options, enabling a client to pay by credit card right from the invoice URL or email. What do you think, is this type of PW profile useful to you or someone you know? I've initially built it towards my own client invoicing needs, but I'm curious what other features you would like it to have? Or do you think it's better to keep it simple so that people can more easily take it in different directions? Thanks for your feedback. Have a great weekend!
    13 points
  2. I don't know if anyone pm'd you already but it can be quite simple if you only need to generate a static svg from a text input. I found this library https://github.com/kartsims/easysvg which would allow you to do it all server-wise if you have .svg font files at hand. My approach would be to have a file input for the font file, a text input for the text you want to generate the svg from, a textarea (closed by default and non-editable) to hold the svg code, and something like https://processwire.com/modules/inputfield-runtime-only/ to echo the textarea's content (the svg) as a preview. Basically a hook in `ready.php`: require "/path/to/easySVG.php"; wire()->addHookBefore("Pages::saveReady", function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); if($page->template->name !== "font") return; // or whatever if(!$page->fontfile && !$page->text) return; // file and text inputs // copy/pasting from easySVG example $svg = new EasySVG(); $svg->setFontSVG($page->fontfile->url); $svg->setFontSize(100); $svg->setFontColor('#000000'); $svg->setLineHeight(1.2); $svg->setLetterSpacing(.1); $svg->setUseKerning(true); $svg->addText($page->text); list($textWidth, $textHeight) = $svg->textDimensions($page->text); $svg->addAttribute("width", $textWidth."px"); $svg->addAttribute("height", $textHeight."px"); $page->svgcode = $svg->asXML(); // textarea input $event->arguments(0, $page); }); And in your `svgpreview` field/file (check RuntimeOnly doc) or template file: echo $page->getUnformatted("svgcode"); (I used getUnformatted in case there are textformatters but it would best if there's none in the field's settings) It's not tested and made on top of my head but I think this might work. (nice to see Velvetyne here btw, I like your work and a good friend of mine made La Savate ?)
    6 points
  3. Hi! We are Velvetyne Type Foundry, since 2010, we’ve designing and distributing free and open source typefaces. We are a non-profit organization. We are quite famous in the world of type design and open source design. We are currently working on a new website. We are focused on performances, and we want to show our fonts as SVG and not webfonts on our home page. Our website is currently using Processwire, and we want to stick to it because it’s amazing. I (author of this post) will take care of most of the development. We need a plugin that is able to generate an SVG path from a font file (present on the server), and a text. This script already does that pretty well and I think it can be a strong base for the font-to-SVG operation. We just want the admin page to be very user-friendly, taking care of the call to the font to SVG script and show its output. I wonder if anyone is able to do such a plugin an how much it can cost. Let me know if you can be interested.
    3 points
  4. Just sharing an admin dark mode theme. Still a WIP, I need to figure out how uikit-inverse colors work and a switcher will be pushed. (great rock job @bernhard) Feel free to try it, submit issue or better pull-request. https://github.com/flydev-fr/AdminStyleDark
    2 points
  5. Dear beta testers, thanks for your help! PAGEGRID is now available here:
    2 points
  6. MagicPages (eg HomePage.php) do now also load the related CSS and JS files (eg HomePage.js and HomePage.css) in the backend page editor ? And there is a new WIKI page about MagicPages: https://github.com/baumrock/RockMigrations/wiki/MagicPages Magic Assets If your page is a MagicPage it will load YourPage.css and YourPage.js files automatically in the PW backend when editing any page of type YourPage. Example: // /site/classes/HomePage.php // /site/classes/HomePage.css div { outline: 2px solid red; } // /site/classes/HomePage.js alert('You are editing the HomePage');
    2 points
  7. For a long time I dived directly in templates and code to build a website. I changed that old workflow and use prototyping and wireframing a website first in Lunacy and Pencil. Only after that I port it to processwire code.
    2 points
  8. Definitely sounds like a job for ProDrafts. Version Control keeps track of changes after they've occurred, but there's no (automatic) way to put them on hold and apply after some action/trigger. In theory one could restore the page to previous revision automatically and step "forward" again once changes are approved, but that would get very complicated very fast, and going back and forth could also result in "conflicts" where updates applied meanwhile would simply get discarded. Anyway, that's not something I would recommend doing ?
    2 points
  9. Hello all, I have released RockFrontendTailwind, an extension module for RockFrontend. It extends Bernhard's module and adds an installation profile for site development with Tailwind CSS. Obviously RockFrontend is a required dependency for my module to work. This module aims to give you a quick start with a Tailwind based project. What RockFrontendTailwind does: A folder "rockfrontendtailwind" will be installed in site/templates. That folder contains all the configuration files needed to get you started with a webpack-based build pipeline for JS and CSS with webpack tailwindcss postcss with postcss-preset-env (for autoprefixing) babel (for transpiling) So rather than just building the CSS with Tailwind, the build pipeline also takes care of transpiling your Javascript based on configuration in a .browserslist file. Of course, the setup is opinionated. But people who are comfortable working with webpack can easily adjust / extend the configuration to their liking. The default configuration watches your JS and CSS files and compiles them into site/templates/assets main.css and main.js by default. All paths are configurable through a .env file. Live reloading during development is not part of the webpack configuration since this is handled by RockFrontend already in a very efficient way. Also a _main.php file including a very basic boilerplate for a typical setup will be placed insite/templates. It includes examples on how to render your JS and CSS assets. More detailed instructions over at github. Adding new profiles to RockFrontend through your own modules is quite straight forward thanks to the clear structure in @bernhard's module. RockFrontendTailwind can serve as a boilerplate. The only important thing is that the "profiles" folder structure remains the same. The module is currently in beta but runs very stable. It will eventually be released as an official module in the directory soon. If you want to give it a shot, I shall be happy to hear your feedback. If you are looking for a standalone webpack build pipeline with webpack-dev-server, you might want to have a look at https://github.com/gebeer/tailwind-css-webpack-processwire-starter Happy Coding!
    1 point
  10. We really like the ability to add redirects via the page editor, but it is annoying that this functionality is only available to superusers. We often have clients asking us to add a 'short url' redirect for a page (e.g. /jobs -> /about/work/jobs) when it really is something they should be able to do themselves. To solve this problem, we've created ProcessPageRedirects. It does two things: Creates a page (Pages > Redirects) which lists all the visible pages to that user and the number of redirects (among other things) Allows them to manage the redirects for pages they can edit The redirects editor is the same one the superuser gets when editing the page. I hope this is useful, let me know here if you come across any issues with it.
    1 point
  11. Looks good @ryan I’ve already built 2 apps with invoicing as part of them. The approach is pretty similar. I used hanna codes quite a bit for the invoice layout. To my mind, the important thing would be the ability to integrate into a wider app (which might, for example, handle products and stock levels). In some ways I think the profile approach is better than a module for this. However, if someone wants to use it in an existing app (or one already in development) we once again hit the issue of “migrations” about which I know there are various views. Ideally you need a way to incorporate the code and database components into another project.
    1 point
  12. This is great. A few years ago I worked briefly for a security company and one of my responsibilities standing in for the accountant when she was off, was billing for services (mainly door security - 'bouncers' here in the UK) and we used an online system very much like this. Some summary pages (monthly/yearly/all time totals etc) would be an obvious addition and tax liability calculations where appropriate perhaps. Of course, being built on top of PW, customisation should be straightforward on this kind of foundation.
    1 point
  13. I’m fully up for supporting this! Amazing work. Wowwwwwwy
    1 point
  14. This might be a somewhat niche module but I had a need for it and maybe others will also find it a useful development helper. Lister To Clipboard Easily copy a selector for the current Lister filters or selected results to the clipboard. For superusers only. Why? Lister or Lister Pro is handy for finding pages according to certain page attributes or field values and you can see the matched pages in a results list. Sometimes I want to run code on some or all the Lister results. Lister Pro allows results to be processed through Page Action modules but there are a couple of downsides to this: To execute custom code you would have to create a custom Page Action module and this may not be worth the trouble for a one-off operation. If you want to process only selected individual pages you can only select items from one page of the results. If you navigate to a different page within the paginated results the selection is lost. Lister To Clipboard gives you an easy way to copy a selector for the current Lister filters or a selection within the results so you can paste it into the Tracy Debugger Console or use it elsewhere in your code. Usage In Lister (Find) or in a Lister Pro instance, create filters to match the pages you want to target. If you want to select individual pages within the results, click an empty area of the cell within the first column (i.e. don't click directly on the page title). The cell will get a green background to indicate that it is selected. If there is more than one page of results you can move around the pagination to select more pages. Below the Lister results there is a blue box showing a selector string that will find the pages shown in your Lister results (or your selection within those results) when used in $pages->find(). Click the copy icon to copy the selector to the clipboard, then you can paste it into the Tracy Debugger Console or wherever you want to use it. https://github.com/Toutouwai/ListerToClipboard https://processwire.com/modules/lister-to-clipboard/
    1 point
  15. 1 point
  16. Thank you very much for your inspiring, and detailed answer @monollonom I am going to make some tests very soon, also I didn’t know the existence of inputfield-runtime-only it solves a blurry area in my view of the process!
    1 point
  17. v2.0.4 improves deployment and thx to another 2 PRs by @gebeer docs and features of permission handling were improved ?
    1 point
  18. @szabesz, the output can't go below the button because the button is not in the results area. But I added a bottom margin so there is some separation from the button.
    1 point
  19. I said, both module require the file `admin.less` or at least the compiled `admin.css` ? But forgot it, my question doesn't make sense as I didn't read the point #3 on AdminStyleRock github repo ?‍♂️ It might serve as an example how to share your own styles with the community in a modular way instead of sharing admin.less files that can't be updated/monitored by the PW upgrades module.
    1 point
  20. Hey @flydev ?? great to see another admin style coming up ? Check out https://github.com/baumrock/AdminStyleRock/ to see how you can create a module for 1-click-install without the need to copy files! This is all you have to add to your module: https://github.com/baumrock/AdminStyleRock/blob/30c91c9832ac8bc54fa64fbee416919824a1983d/AdminStyleRock.module.php#L35-L53
    1 point
  21. Hi, hope this helps: https://processwire.com/talk/topic/15282-help-for-first-project/#comment-136758
    1 point
  22. README lists three supported multilingual fieldtypes: Text (regular and multi-language) Textarea (regular and multi-language) Page Title (regular and multi-language) Technically other multilanguage fieldtypes should be supported as well, but these are the ones I've tested. Version Control has a config setting for enabling fieldtypes that are available on the site, but not listed as compatible by default.
    1 point
  23. You can use the URL-Hooks. https://processwire.com/blog/posts/pw-3.0.173/ I think this should be the simplest solution.
    1 point
  24. @mel47 I got it right. For use: I include the php file in the header. It's for a Bootstrap 4 site but I'd imagine Bootstrap 5 would be very similar. Note: I did have an issue with a nav padding on "sm devices" which I couldn't resolve in the php output. In the end I added an additional rule to my css to fix it. A bit of a hack but it's working. @media (max-width: 992px) { li.nav-item { padding-left: 30px; } } And here is the php <?php namespace ProcessWire; function buildMenuFromObject($parent = 0, $menu, $first = 0) { if(!is_object($menu)) return; $out = ''; $has_child = false; foreach ($menu as $m) { $newtab = $m->newtab ? " target='_blank'" : ''; // if this menu item is a parent; create the sub-items/child-menu-items if ($m->parentID == $parent) {// if this menu item is a parent; create the inner-items/child-menu-items // if this is the first child if ($has_child === false) { $has_child = true;// This is a parent if ($first == 0){ $out .= "\n<ul class='navbar-nav plain mx-auto text-center'>"; $first = 1; } else { $out .= "\n\t" . "<ul class='dropdown-menu'>"; } } // active/current menu item $class = $m->isParent ? ' class="nav-item dropdown"' : ' class="nav-item"'; $aClass = $m->isParent ? 'class="dropdown-item dropdown-toggle"' : 'class="dropdown-item"'; // a menu item $out .= "\n\t<li$class><a {$aClass} href='{$m->url}' '{$newtab}'>{$m->title}</a>"; // call function again to generate nested list for sub-menu items belonging to this menu item. $out .= buildMenuFromObject($m->id, $menu, $first); if ($m->isParent) $out .= "\n";// close li $out .= "</li>"; }// end if parent }// end foreach if ($has_child === true) $out .= "\n\t</ul>"; return $out; } $menu = $modules->get('MarkupMenuBuilder'); $menuItemsAsObject = $menu->getMenuItems('Main', 2);//Where "Main" is the name of the menu to output $menu = buildMenuFromObject(0, $menuItemsAsObject); ?> <div id="gregnav"> <nav class="navbar wide transparent transparent-light navbar-expand-lg"> <div class="container-fluid flex-row justify-content-center"> <div class="navbar-header"> <div class="navbar-brand"><a href="index.html"><img src="#" srcset="<?php echo $config->urls->templates?>style/greg-images/GL-black-square60.png 1x, <?php echo $config->urls->templates?>style/greg-images/GL-black-square75.png 2x" alt="" /></a></div> <div class="navbar-hamburger ml-auto d-lg-none d-xl-none"><button class="hamburger animate" data-toggle="collapse" data-target=".navbar-collapse"><span></span></button></div> </div> <!-- /.navbar-header --> <div class="navbar-collapse collapse justify-content-between align-items-center"> <?=$menu?> </div> <!--/.social-wrapper --> </div> </nav> </div> I hope that helps you. ?
    1 point
  25. Thx to @gebeer we now have support for repeater fields in the new version of RockMigrations ? If you find any other features that have been implemented in RM1 that are not yet in RM2 please let me know or even better create a PR ? Bumped version to 2.0.0 as I just realised that this version number fits better to how I'm referencing RM1 and RM2!
    1 point
  26. I feel like a oldschool nerds ?‍♂️ listen bits in loop for motivation (https://m.pouet.net/ - http://www.bitfellas.org/) start coding in js and you end up writing asm ?
    1 point
  27. I'm always listening to Radio Paradise. Will check NTS Radio out, sounds interesting. ?
    1 point
  28. I like a little bit of chaos personally. Can I stick a vote in for NTS Radio - they have a fantastic range of music.
    1 point
  29. Yeah great songs. But to bring order to the chaos, it must be JS Bach.
    1 point
  30. Look at this example. Its made with the old version of RestAPI first made by @thomasaull years ago. To get the context, you can navigate to https://kingspark.fr and https://valideur.mykingspark.fr . I am speaking about a system which give the possibility to some of our client use their mobile or a barcode scanner device to give "free of charge parking" of their customer. Its composed with custom hardware, software and devices or mobile apps (you see it on GooglePlay). Image #1: List of Parkings // Image #2: The custom made SAGAS Terminal // Image 3: A configured User / Device available for registration and use. On the first picture, you can see a list of "Parkings", and some can have the "Valideur" functionality. We can configure attached devices and some users with specific role to get access for registration. And then, imagine the following. A customer land on the parking, grab a ticket and go to their rendezvous At the end, the guy in the office use his "Barcode Scanner" to "validate" the ticket of the customer; This mean that the customer will not pay anything when landing on the terminal to exit the parking, and when he will present the ticket on the barcode-reader installed on the terminal (the "black hole" you can see on the center in the picture), it will be recognized by another software and thought a call on ProcessWire Rest API backend. I made you two screencasts, the first is the software which once installed and registered, get the quota (number of validation available) from the user assigned to the license-code, and the second is my mobile which get notification sent from ProcessWire (by this module) from a monitoring system to get real-time information on registration. If you have any question, do not hesitate. There a more example, but you should get the whole idea ?
    1 point
  31. Hi @kongondo, after setting some of our PHP environments to 8.0, we registered an error on deleting menu items (ProcessWire 3.0.200, MenuBuilder 0.2.7, Multi-language): method_exists(): Argument #1 ($object_or_class) must be of type object|string, null given in line 2602 in ProcessMenuBuilder.module. To prevent this, a check for item related page existence was successful: if (!$itemID || !$pages->get($itemID)->id) continue; Could you publish a bug fix release für this issue, please? Thanks in advance, Thomas from xport.
    1 point
  32. This is how I did it: $mb = $modules->get('MarkupMenuBuilder'); $items = $mb->getMenuItems('Main', 2); foreach ($items as $item) : if ($item->isCurrent) : $currentID = $item->id; $parentID = $item->parentID; endif; endforeach; $subItems = $items->find("parentID=$parentID"); foreach ($subItems as $subItem) $output .= '<a href="'.$subItem->url.'">'.$subItem->title.'</a>';
    1 point
  33. This basic tutorial is primarily aimed at those new to PW. It could also serve as a reference to others more seasoned PW users. The question about how to categorise content comes up in the forums now and again. Hopefully with this post we’ll have a reference to guide us right here in the tutorials board. Many times we need to organise our site content into various categories in order to make better sense of the data or to logically and easily access it. So, how do you organise your data when you need to use categories? Here are a few tips gathered from the PW forums on how to go about this. Using these tips will, hopefully, help you avoid repeating yourself in your code and site content and keep things simple. See the links at the end of this post to some useful discussion around the topic of categorisation. Before making decisions about how to organise your site, you need to consider at least three questions: What items on my site are the main items of interest? These could be people or things (cars, plants, etc.). In most cases, these are the most important content on which all the other stuff point to. Where do items need to be grouped into categories? This is about where items need to “live”. It is about the attributes of the items of interest (e.g. responsibilities, job types, colour, etc.). Attributes can have sub-attributes (e.g. a category job type = driver could be further sub-classified as job type role = train driver). Can they live in more than one place? - This is about having multiple attributes. There could be other issues such as the type of content your main items of interest are but that’s for another post. We’ll keep these examples simple. The main principles explained below still apply. There are at least three possible ways in which you can organise your content depending on your answers to the above three questions. These are: Single category Simple multiple categories Complex multiple categories These are illustrated below. Note that this is what I call them; these are not PW terms. 1. Single Category Suppose you need to do a site for a company that’s made up of several Departments each with employees performing unique functions. These could include “Finance”; “Media Communications”; “Administration”; “Technicians”; “Human Resources”; “Logistics”. We ask ourselves the following questions based on our 3 questions above: 1. Q: What items on my site are the main items of interest? A: Employees. 2. Q: What attributes of our items of interests are we interested in? A: Departments. (Single main category) 3. Do the Departments have sub-categories? A: Yes. (Multiple sub-categories) 4.Can Employees belong to multiple sub-categories? A: No. (Single sub-category) We conclude that what we need is a Single Category model. Why? This is because, in Single Categories model, items of interest can only belong to 1 and only 1 main/parent category and within that only 1 sub-category Employees in this company can only belong to one and only one department. Finance guys do their finance and Logistics guys do their stuff. Letting Techies do press conferences is probably not going to work; that we leave to the Media guys . Assuming the company has the following employees - James, John, Mary, Ahmed, Peter, Jason, Barbara etc., arranging our site content to fit this model could look like the following: Items of interest = Employees Categories = Departments Adopting out strategy to keep it simple and logical, let us write down, hierarchically, our employee names against their departments to mimic the PW tree like this: James Finance John Finance Mary Technician Ahmed Logistics Barbara Media Etc. We notice, of course, that departments start repeating. It doesn't look like we are doing this very logically. If we think about this carefully, we will conclude that, naturally, the thing (attribute in this case) that keeps repeating should be the main criteria for our categorisation. This may seem obvious, but it is worth pointing out. Also, remember, that as per the responses to our questions, the categories (Finance, Logistics, etc.) do not have sub-categories. In this aspect, we are OK. Using this principle about repeating attributes, we find that Departments, rather than Employees, need to be the main categories. Hence, we categorise our PW site content by doing the following. Create a template for each Department. Hence, we have a template called Finance, Logistics, etc. Add the fields needed to those templates. This could be a text field for holding Employee phone numbers, email field for email, title field for their names, etc. Create top level pages for each Department and assign to them their respective templates. Give them appropriate titles, e.g., Finance, Media, etc. Create a page for each employee as a child page of the Department which they belong to. Give them appropriate titles, e.g. James, John, etc. We end up with a tree that looks like this: 1. Finance (ex. main category) a. James (ex. item of interest) b. John c. Shah d. Anne 2. Logistics (ex. main category) a. Ahmed b. Matthew c. Robert d. Cynthia 3. Media a. Barbara b. Jason c. Danita 4. Human Resources a. Michael b. Pedro c. Sally 5. Technician a. Mary b. Oswald c. Dmitri d. Osiris Since an employee can only belong to one Department, our work here is done. We can then use PW variables, e.g. $page->find, $pages->find with the appropriate selectors to find employees within a Department. This is a very basic example, of course, but you get the idea. You have the choice of creating one template file for each category template as well. I prefer the method of using one main template file (see this thread). You could do that and have all Departments use different templates but a single template file. In the template file you can include code to pull in, for example, the file “technician.inc” to display the relevant content when pages using the template “Technician” are viewed. Example code to access and show content in Single Categories model $hr = $pages->find("template=human-resources, limit 50"); foreach ($hr as $h) { echo "{$h->title}"; } But sites do not always lend themselves to this model. Many times, items of interest will need to belong to multiple categories. 2. Simple Multiple Categories Let’s say you were building a site for cars - red cars, blue cars, 2-seaters, 5-seaters, etc. Again, we ask ourselves our questions based on our initial three questions: 1. Q: What items on my site are the main items of interest? A: Cars. 2. Q: What attributes of our items of interests are we interested in? A: Colour, Number of seats, Models, Year of manufacture, Types. (Multiple categories) 3. Do these multiple attributes have sub-attributes? A: Yes. e.g., the attribute Colour has several sub-categories - red, white, green, etc. (Multiple sub-categories) 4. Can Cars have multiple sub-attributes? A: No. e.g., a yellow car cannot be a green car. (Single sub-categories) We therefore conclude that what we need is a Simple Multiple Category model. Why? This is because, in Simple Multiple Categories, items of interest can belong to multiple parent categories. However, within those parent categories, they can only belong to one sub-category. Assuming we have the following cars, manufactured between 2005 and 2008, as items of interest: Mercedes, Volvo, Ford, Subaru, Toyota, Nissan, Peugeot, Renault, Mazda, arranging our site content to fit this model could look like the following: Items of interest = Cars Categories = Model, Year, Colour, Number of seats, Type Sub Categories = Model [Prius, etc.]; Year [2005, 2006, 2007, 2008]; Colour [Red, Silver, Black, White, Green]; Number of seats [2, 5, 7]; Types [sports, SUV, MPV]. Adopting out strategy to keep it simple and logical, if we wrote down our cars names against their attributes like this: Mercedes Model-Name: Year: 2005 Colour: Silver Seats: 2-seater Type: Sports Volvo Model-Name: Year: 2007 Colour: Green Seats: 5-seater Type: SUV Ford Model-Name: Year: 2007 Colour: Red Seats: 7-seater Type: MPV Etc We notice, again, that car attributes start repeating. In order not to repeat ourselves, we want to avoid the situation where our child pages “names” keep repeating. For instance, in the above example tree, we want to avoid repeating year, colour, etc. within the tree. Of course in the frontend our output needs to look like the above where we can list our cars and their respective attributes. We just don’t need a tree that looks like this in the backend. Since we have multiple categories and sub-categories, we need to rethink our strategy for categorising our content as illustrated below. The strategy we used in the first category model will not work well here. Hence, these repeating attributes (year, colour, etc.) need to be the main criteria for our categorisation. We need to end up with a tree that looks like this: 1. Cars a. Mercedes (ex. item of interest) b. Volvo c. Ford d. Subaru e. Toyota f. Range Rover g. Peugeot h. Renault i. Mazda 2. Model (ex. main category) a. Fiesta (ex. sub-category) b. Miata c. Impreza d. Matrix e. Prius f. E-Class g. XC-90 h. Scenic i. L322 j. 505 3. Year a. 2005 b. 2006 c. 2007 (ex. sub-category) d. 2008 4. Colour a. Red b. Silver c. Black d. White e. Green 5. Number of Seats a. 2 b. 5 c. 7 6. Type a. MPV b. Sports c. SUV d. Other At the top of the tree, we have our main items of interest, Cars. They do not have to come first on top of the tree like that but it just makes sense to have them like this. Next, we have the Cars’ categories (attributes). The main categories are parent pages. Each main category has children which act as its sub-categories (cars’ sub-attributes). For instance, the main category colour has sub-categories “red”, “green”, etc. Grouping them under their main category like this makes better sense than having them dangling all over the tree as parent pages themselves. Now that we know what we want to achieve, the next question is how do we go about relating our categories and sub-categories to our main items of interest, i.e., cars? Fields come to mind. OK, yes, but what about the sub-categories (2006, red, 5-seater, etc.)? Surely, we can’t keep typing those in text fields! Of course not; this is PW. We like to simplify tasks as much as we can. What we need is a special type of field. Page Reference Fields or Page Fieldtypes add the ability to reference other pages, either single or multiple pages, within a page. For instance, we could have a Page Reference Field in the template that our Car pages use. Let’s call this “car-template”. When viewing Car pages, we would have the ability to select other pages on our site that we wish to reference, for instance, because they are related to the page we are viewing. In other cases, we could also wish to reference other pages that contain attributes/values of the page we are viewing. This is the situation with our Cars example above. Hence, the sub-categories/sub-attributes for our Cars will be pulled into our car pages using Page Reference Fields. There are two types of Page Reference Fields; single page and multiple pages. What each do is obvious from their names. Single Page Reference Fields will only reference one page at a time. Multiple Page Reference Fields will reference multiple pages. OK, let’s go back to the issue at hand. We need to categorise Cars by various attributes. Do we need to reference the main categories (Year, Type, etc.) in our Car pages? In fact, we don’t. What we need to reference are the sub-categories, i.e. 2005, red, SUV, etc. These will provide the actual attributes regarding the parent attribute of the Cars. We have said we do not wish to type these sub-categories/attributes all the time hence we use Page Reference Fields. Which type of Page Reference Field should we use? Remember that our Cars can have only one sub-category/sub-attribute. That’s our cue right there. In order to select one and only one sub-attribute per Car, we need to use the single Page Reference Field. Hence, we categorise our Cars PW site by doing the following (you may follow a different order of tasks if you wish). Create a template to be used by the Car pages. Give it a name such as car-template Create a page for each of your cars and make them use the car-template Create one template to be used by all the main attribute/categories and their children (the sub-categories). We do not need a template for each of the categories/sub-categories. I name my template “car-attributes” Of course you can name yours differently if you wish. Add the fields needed to this template. You don’t need anything other than a title field for each actually. Create top level pages for each main category and assign to them the template car-attributes. As before, give your pages meaningful titles. Do the same respectively for their child pages. E.g., you should have the following child pages under the parent “Year” - 2005, 2006, 2007 and 2008. Create the Page Reference Fields for each of your main categories/parent attributes. Using our example, you should end up with 5 Page Reference Fields (model, year, colour, seats and type). Each of these should be single Page Reference Fields. It’s a good idea, under the BASICS settings while editing the fields, to include some Description text to, include additional info about the field, e.g. instructions. In addition, you don’t want any page that doesn't belong to a particular attribute to be selectable using any of the Page Reference Fields. For instance, when referencing the year a car was manufactured, we want to be able to only select children of the page Year since that is where the year sub-categories are. We do not want to be able to select children of Colour (red, green, etc.) as the year a car was manufactured! How do we go about this? PW makes this very easy. Once you have created your Page Reference Fields, while still in the editing field mode, look under the settings INPUT. The fourth option down that page is “Selectable Pages”. Its first child option is “Parent of selectable page(s)”. Where it says “Select the parent of the pages that are selectable” click on change to change the parent. By now you know where I am going with this. For the Page Reference Field named Year, choose the page “Year” as the parent whose children will be selectable when using that Page Reference Field to select pages. Similarly, do this for the remaining 4 Page Reference Fields. Note that under this field settings INPUT you can change how you want your pages to be selectable. Be careful that you only select the types that match single Page Reference Fields, i.e. the ones WITHOUT *. For single Page Reference Fields, you have the choices:Select - a drop down select Radio buttons PageListSelect Now edit the car-template to add all 5 of your Car Page Reference Fields. We are now ready to roll. Go ahead and edit your Car pages. In each of them you will see your 5 Page Reference Fields. If you followed the instructions correctly, each of them should only have the relevant child pages/sub-attributes as selectable. Do your edits - select year when car was manufactured, its colour, type, number of seats, etc. and hit Save. By the way, note that Page Reference Fields give you access to all the fields and properties of the page being referenced! You have access to the referenced page’s title, name, path, children, template name, page reference fields, etc. This is really useful when creating complex sites. I call it going down the rabbit hole! These properties of the referenced page are available to you on request. It does mean that you will have to specifically echo out the property you want from that page. Page Reference Fields are echoed out like any other field. Example code to access and show content in Simple Multiple Categories model $cars = $pages->find("template=car-template, limit=10, colour=red, year=2006, seats=5"); foreach ($cars as $car) { echo $car->title; echo $car->year; echo $car->colour; } I have made the above verbose so you can easily follow what I'm trying to achieve. The above code will find 10 red 5-seater cars manufactured in 2006. Remember, colour, year and seats are the names of your custom Page Reference Fields that you created earlier. Some sites will have content that belong to multiple categories and multiple sub-categories. We address this below. 3. Complex Multiple Categories Suppose you are developing a site for a school. The school has teachers (duh!) some of whom teach more than one subject. Besides their classroom duties, some teachers are active in various clubs. On the administration side, some teachers are involved in various committees. You know the drill by now. Let’s deal with our basic questions. 1. Q: What items on my site are the main items of interest? A: Teachers. 2. Q: What attributes of our items of interest are we interested in? A: Subjects, Administration, Clubs (Multiple categories) 3. Do these multiple attributes have sub-attributes? A: Yes. e.g., the attribute Subjects has several sub-categories - History, Maths, Chemistry, Physics, Geography, English, etc. (Multiple sub-categories) 4. Can Teachers have multiple sub-attributes? A: Yes. e.g., a Teacher who teaches both maths and chemistry (Multiple sub-categories) Apart from the response to the final question, the other responses are identical to our previous model, i.e. the Simple Multiple Categories. We already know how to deal with multiple categories so we’ll skip some of the steps we followed in the previous example. Since our items of interest (Teachers) can belong to more than one sub-category, we conclude that what we need is a Complex Multiple Category model. In Complex Multiple Categories, items of interest can belong to multiple parent categories and multiple sub-categories both within and without main/parent categories. By now we should know what will be the main criteria for our categorisation. We need to end up with a tree that looks like this: 1. Teachers a. Mr Smith (ex. item of interest) b. Mrs Wesley c. Ms Rodriguez d. Mr Peres e. Mr Jane f. Mrs Potter g. Ms Graham h. Mrs Basket i. Dr Cooper 2. Subjects (ex. main category) a. History (ex. sub-category) b. Maths c. English d. Physics e. Chemistry f. Geography g. Religion h. Biology i. French j. Music 3. Clubs a. Basketball b. Debate c. Football d. Scouts e. Sailing f. Writing 4. Administration a. Discipline b. Counselling c. Exams board d. Public relations e. Education We are ready to build our site. Which type of Page Reference Field should we use? Remember that our Teachers can teach more than one subject and can be involved in various sub-category activities. That’s our cue right there. In order to select multiple attributes/categories, we of course go for the multiple Page Reference Field. Similar to the previous example, create necessary templates and fields for the site. For our multiple Page Reference Fields, remember to select the correct input field types. These should match multiple Page Reference Fields and are marked with *. For multiple Page Reference Fields, the available choices are: Select Multiple* AsmSelect* Checkboxes* PageListSelectMultiple* PageAutoComplete* Remember to add the multiple Page Reference Fields to the Teachers template. Go ahead and test different selectors, e.g. find Teachers that teach Maths and Chemistry and are involved in the Writing club. Whether you get results or not depends on whether there is actually that combination. An important point to remember is that your multiple Page Reference Fields will return an array of pages. You will need to traverse them using foreach (or similar). Example code Complex Multiple Categories model Find the subjects taught by the Teacher whose page we are currently viewing. You can use if statements to only show results if a result is found. In this case, of course we expect a result to be found; if a Teacher doesn't teach any subject, he/she has no business teaching! subjects is the name of one of your custom Multiple Page Reference Fields. echo "<ul>"; foreach ($page->subjects as $x) { echo "<li>{$x->title}</li>"; } echo "</ul>"; There will be situations where you will need to use both Single and Multiple Page Reference Fields (independently, of course). For instance, in our Teachers example, we might be interested in the Gender of the Teacher. That would require a Single Page Reference Field. Summary What we have learnt: Categorising our site content need not be a nightmare if we carefully think it through. Of course not all sites will fit neatly into the 3 models discussed. By providing answers to a few simple key questions, we will be able to quickly arrive at a decision on how to categorise our content. There are at least 3 models we can adopt to categorise our content - single category; simple multiple category; and complex multiple category. In the latter two models, we make full use of PW’s powerful Page Reference Fields to mimic a relational database enabling us to roll out complex sites fast and easy. Useful links: http://processwire.com/talk/topic/3553-handling-categories-on-a-product-catalogue/ http://processwire.com/videos/create-new-page-references/ http://processwire.com/videos/page-fieldtype/ http://processwire.com/talk/topic/1041-raydale-multimedia-a-case-study/ http://processwire.com/talk/topic/683-page-content-within-another-page/ http://processwire.com/talk/topic/2780-displaying-products-category-wise/ http://processwire.com/talk/topic/1916-another-categories-question/ http://processwire.com/talk/topic/2802-how-would-you-build-a-daily-newspaper/ http://processwire.com/talk/topic/2519-nested-categories/ http://processwire.com/talk/topic/71-categorizingtagging-content/ http://processwire.com/talk/topic/2309-best-way-to-organize-categories-in-this-case/ http://processwire.com/talk/topic/2200-related-pages/ http://processwire.com/talk/topic/64-how-do-you-call-data-from-a-page-or-pages-into-another-page/
    1 point
×
×
  • Create New...