PrevProcessWire 2.5.7 creepy core updates
AJAX file upload drafts. Field/template context now available for any field property. Configurable labels for "Content" and "Children" tabs in page editor… and more. More
In ProcessWire there is no set limit on how many custom fields you can create. But fields are not meant to scale infinitely in the way that pages are. Thousands of fields will not scale as well as thousands of pages (for the system or for you). In this article we'll attempt to outline some of the best practices for making efficient use of fields in ProcessWire and how to optimize your use.
Consider the following:
Given these factors, here are some things you can do to optimize the use and quantity of fields necessary to meet the needs of your site or application.
I very often see sites that contain a lot of individual checkbox fields for various toggles for things that can be turned on or off on a page. These are great for that purpose, but if you get to the point of having 3 or more of them (or want to plan for more) you may be better off using a Page field instead.
Using a page field, you can convert any number of checkbox toggle fields into a single Page field:
Your next question might be how to use it on the front-end of your site? It's a little different than how you'd use individual checkbox fields, but it's also more flexible. Because the value of the checkbox field is just a PageArray, there are any number of ways to see what it contains, but I usually like to refer to the "name" property because it remains easily readable in the code. As an example, lets say that I wanted to check if a toggle named "featured" is set on the current page:
if($page->toggles->get("name=featured")) {
// this page has the "featured" toggle set
}
Another case might be that you just want to render a list of all toggles active for the current page. In this case, we'll use the "title" of each toggle since it's formatted better for reading:
foreach($page->toggles as $toggle) { echo $toggle->title . "<br>"; }
And another alternative for those that like less-readable 1-line statements:
echo $page->toggles->implode("<br>", "title");
To reiterate, you can combine any number of individual checkbox fields into a single Page field. If you are replacing a lot of individual checkboxes, this can be significantly more efficient, not to mention easier to scale and maintain.
If you are using a lot of separate single-file fields in a given template, consider combining them all into just one multi-file field, and enable the "tags" option. By "multi-file", I mean setting your files field to have no maximum (specified by "0"), and setting the "Formatted Value" to be "Automatic" or "Array", both visible on the Details tab when editing your files field. The tags option can also be seen here, under "Use Tags?". Check the box to use tags and you now have a way to specify what each file in that field is for.
Lets say that you were building a website selling homes and you want to separately identify which photos are for inside and outside the home (interior and external). You might like to go further and separately identify kitchen, bathrooms, bedrooms, etc., but lets just focus on inside and outside for the moment. Do note however that you can have any number of tags for each file. When uploading files to your files field, you can designate each photo as interior or external just by entering the tag "interior" or "exterior". Typically you'd instruct the user uploading files on what tags they should use in your file field's description.
On the front-end of your site, you could output all the interior photos as a group and all the exterior photos as a group, while still having them all in the same files field. Here's how:
echo "<h3>Exterior Photos</h3>"; foreach($page->photos->findTag("exterior") as $photo) { echo "<img src='$photo->url' alt='$photo->description' />"; } echo "<h3>Interior Photos</h3>"; foreach($page->photos->findTag("interior") as $photo) { echo "<img src='$photo->url' alt='$photo->description' />"; }
Lets say that you also wanted to let the editor designate one of the photos as the big cover photo at the top of the page, using the tag "cover". If there was no photo with that tag, then you'd just use the first photo.
$cover = $page->photos->getTag("cover"); if(!$cover) $cover = $page->photos->first(); echo "<img src='$cover->url' alt='$page->title' />";
If you've got similar fields across multiple templates (in terms of what is stored and input), consider using a general purpose field across multiple templates rather than separate template-specific fields. Most of our site profiles include fields like "title", "body" and "summary", which are good examples of this. Avoid using single-template specific fields, like "product_body", "company_summary", etc. (when possible), because you can simply re-use a general purpose field shared across multiple templates.
For every field that you create, always think about the bigger picture and how you might utilize that field in a broader context across multiple templates, whether now or in the future. I'm not suggesting you start creating fields with names like textarea1, textarea2, textarea3, etc., as that would be entirely too general purpose and be unintelligible from the code side. But I do see a lot of instances where people create the same field over and over again separately for each template, and that definitely calls for more consideration of field reuse.
As a bonus, using more general purpose fields improves code reusability. If you've got a block of code that generates some output, it may be able to cover a broader range of page templates if there is some common ground in field names across templates.
Do you ever find yourself creating new fields simply so that it can have a different label, description, required state, etc.? If so, there's no need to. ProcessWire provides you with something called field template context that lets you customize any aspects of the field as it's shown to the editor, separately for each template. Just for starters, you can have a field named "body" labeled as "Body Copy" in one template, and "Product Description" in another, and it's incredibly easy to do.
To use field template context, go and edit any template (Setup > Templates > any template). Click on any of the field names shown in the template and it will pop up a window that enables you to customize several aspects of that field that only apply within the context of the template you are editing.
ProcessWire comes with two separate Fieldtypes that let you create repeatable blocks of fields: PageTable and Repeaters. We could write an entire book on all that you can do with these, so rather than getting too far into it here, we'd suggest that you experiment and see the potential yourself. Neither of these are installed by default, but they do come with the core. Simply go to Modules > Core > Fieldtype and install them both. Once installed, usage is fairly self explanatory, but take your time and explore, as there is a lot of power and likewise potential for efficiency.
Repeaters are a little easier to configure initially, but PageTable fields are ultimately more powerful. If you don't want to learn them both, then focus in on PageTable. In either case, the repeatable items in each of these fields are themselves pages that can contain any group of fields you desire. PageTable goes even further and enables you to have a single PageTable field that can publish pages using different templates from within the same field.
ProcessWire ProFields is one of our commercial modules that is designed specifically for the purpose of letting you do more with fewer fields. Because a lot has been written on these already, I will link to the relevant information rather than repeat it here:
You can meet any data storage or input need by creating your own fields. After all, ProcessWire fields are just plugin modules, and you can always create your own custom modules to meet your specific needs. Admittedly, this is not for everyone, but if you don't mind getting your hands a little dirty with some PHP, you can literally do anything. In fact, ProcessWire was designed from the beginning to be extended in just this way.
As an example of how a custom Fieldtype/Inputfield might be beneficial in reducing fields, consider what it takes to represent an individual's contact information. You may need separate fields for: first_name, last_name, phone, email, company, address1, address2, city, state, zip, and country, and maybe more. That's at least 11 separate fields that could be represented by a single custom aggregate field. This can be accomplished relatively easily by creating a custom Fieldtype to manage and store the data, and a a custom Inputfield to provide input for it in the admin.
What it takes to create custom Fieldtypes and Inputfields is beyond the scope of this document, but there are numerous examples both in the core and 3rd party for you to look at. We've also created a custom one called the Events Fieldtype purely for demonstration purposes.
If you have a custom field need, but don't feel comfortable creating your own, post in our jobs board and you'll be able to find someone that would be happy to create it for you.
What other ways have you found work well in making efficient use of fields in ProcessWire? This article just covers a few things, but there are certainly more possibilities.
31 October 2014 4
AJAX file upload drafts. Field/template context now available for any field property. Configurable labels for "Content" and "Children" tabs in page editor… and more. More
7 November 2014 1
This week we added modal tab support to the page editor. For sites with a lot of fields, the performance improvements are massive. More
“We were really happy to build our new portfolio website on ProcessWire! We wanted something that gave us plenty of control on the back-end, without any bloat on the front end - just a nice, easy to access API for all our content that left us free to design and build however we liked.” —Castus, web design agency in Sheffield, UK
Francesco
The "Use Page fields rather than individual checkboxes" tip is really cool. Though it has one big disadvantage: With this approach it is pretty difficult to work with Inputfield Dependencies as subfields are not supported yet, except for ".count". A check for "toggles.name=featured" is not possible.
Reply
Can
Don't know one year ago, but it's working for me. Wrote it just for completeness ;-)
Reply
Sebastian
Very helpful, thanks! I was always wondering if I should separate fields with a particular purpose (on a template) or make it more general at the beginning to reuse it (on other templates with a different usage).
Reply
martin
I agree, very helpful and should be placed in the docs or rather tutorials section. One of my personal favorites will be the possibility to use the editor (with inline mode) inside the Pro Table-Fieldtype some day.
Reply