Locations Organized by State in Craft CMS

November 30, 2017

This is a story of coming up with a better solution for a project. Even the best developers need to refactor their code and rethink a solution. There are many reasons this might be so.

  • We did not fully understand or understand the problem rightly on the first pass
  • The client had modified or added to the scope of the project once development was started or parts of it were finished
  • We are not given enough information about the live use case until late in the project or after it has been handed over to the client
  • Through use and time, we learn better ways we could have solved the problem than at the time we initially tried to solve it

Many of the projects that I work on I build using a CMS that the client will add content to after the project is handed over or the content is added after the bulk of the development is already done and the site is close to launch. I am not complaining but observing the very real-world way that websites get built by freelance contractors like myself. As Rachel Andrew would say, “This isn’t our fault. However the responsibility of dealing with the problem well, and in a way that benefits others, is very much our problem.”

I was involved in a project two years ago where I was contracted to build out a design for a careers website for Sun Communities. They provide property management and development in locations around North America. I was given mock-ups for the different pages they wanted on the site. The agency that I partnered with had started using Craft CMS for our build solutions.

One of the pages of the site was a listing of all the different locations that Sun Communities operated. The design solution called for a listing by state and with the number of locations underneath the name of the state. The individual locations would be shown by toggling a button with a label of “View Locations.” The design also called for a state icon for a quick visual cue as to the state or province.

Original design mockup

Because there was an icon for each different state, the designer created a mock-up with all the states. Most states had only 1-4 locations according to the mock-up with a couple having 15, 33, or 68 locations. There was an example of the toggled locations and the locations were not in alphabetical order. I assumed that order was not going to matter.

Original Solution

I had only built a handful of sites in Craft so far so I was still learning about how to best make use of its different fields. I decided to build out this page by creating a “Location content type. Each location entry would be a different state or Canadian province. I then decided to build the individual locations as a Matrix content block. The user would enter the information for each location with a new matrix. The user could add as many different matrix blocks as they needed and could sort them using the drag-and-drop interface.

Matrix field block and button to add another Matrix field

I had used the matrix block in this way on some other projects and at the time, it was the only solution that came readily to mind.


<article class="show-locations">
  <ol>
    {% for block in location.officeLocations %}
    {% if block.type == "officeLocation" %}
    <li>
      <article class="vcard">
        <span class="org">
          <span class="hide" aria-hidden=true> Sun Communities </span>
          {% if block.searchPageUrl|length %}<a href="{{ block.searchPageUrl }}">{% endif %}{{ block.locationName }}{% if block.searchPageUrl|length %}{% endif %}
          <span class="hide" aria-hidden=true> Office</span>
        </span>
        <span class="adr">
          <span class="street-address">{{ block.locationStreetAddress }}</span>
          <span class="locality">{{ block.locationCity }}</span>, 
          <span class="region">{{ location.title }}</span> 
          <span class="postal-code">{{ block.locationZip }}</span>
        </span>
      </article>
    </li>
    {% endif %}
    {% endfor %}
  </ol>
</article>

Code from Craft template

Houston, We have a problem

Some cracks in my solution began to show when we got a listing of all the locations as we were preparing to launch the site. Many of the states had more than just a handful of locations. On the current site (not the one I developed), Florida has a total of 122 locations. The client also put in the request that the locations appear alphabetically. This was not too difficult to accomplish in the initial solution because we could just enter them in order. But when they added some more locations, I realized that the drop-and-drag ordering was not easy to do when there were so many entries. Each new entry would appear at the bottom and need to be dragged to its correct position to have the order the client desired.

As with a lot of projects, there were several things we needed to address to get the site launched so there was not time to rethink the individual location entries.

Several months later, we had a problem when syncing the database for another component to the project and the locations reverted to an earlier point. I had to go in late one night and add back in the locations that were missing and sort them using the drag-and-drop. It was a real pain point for me and it bothered me knowing that the solution I had chosen to implement was falling short. But we were only getting paid to fix the immediate problem which was to add back in the content that was not in the earlier version of the database.


Note on February 2, 2024: I never did finish this posting. But I want to save it for posterity’s sake. So I am going to try to wrap this up by describing how I addressed and solved this problem. Unfortunately, I no longer have access to a working copy of the site so I will not have the screenshots that I originally had planned for the post.


A new solution

My idea was to recode this solution so that the office locations would have their own content type and then be dynamically added to each state location listing. I needed a way to create a relationship between the state location and the individual office location so that I could display the office locations under the correct state.

After doing a Google search, I found an article on the Straight Up Craft site by Ben Parizek. He walked me through how to do the very thing that I needed to pull off the solution that I envisioned. CraftCMS had a relatedTo() parameter that enabled me to make the connection. I believe I had a field in the individual office locations that allowed me to assign it to one of the state locations but it has been over six years so I don’t remember the specifics now.

Here is my updated template code:

{% extends "_layout" %}
{% block content %}
  <div id="content" role="main">
    <div class="wrapper">
      <h1 class="page-title">Search {{ entry.title }}</h1>
      <div id="location-content">
        <ol>
	{% for location in craft.entries.find({section: 'Location', order: 'title asc'}) %}
        {% set facilityLocations = craft.entries.section('individualLocations').relatedTo(location).order('title') %}
        {% if facilityLocations | length %}
	  <li class="{{ location.title|replace(' ','-')|lower }}">
	    <article class="header">
	      <i class="icon"></i>
	      <div class="content">
		<h2><a href="/search?keywords=&location={{ location.title|replace(' ','+') }}">{{ location.title }}</a></h2>
		{% set numberLocations = 0 %}
		{% for facility in facilityLocations %}
		  {% set numberLocations = numberLocations + 1 %}
	        {% endfor %}
		<p class="number-of-locations">{{ numberLocations }} {% if numberLocations == 1 %} Location {% else %} Locations {% endif %}</p>
		<a href="{{ location.url }}" class="location-button">Jobs in {{ location.title }}</a>
	       </div>
             </article>
	     <article class="show-locations">
		<ol>
		{% for facility in facilityLocations %}
		  <li>
		    <article class="vcard">
			<span class="org">
			  <span class="hide" aria-hidden=true>Sun Communities </span>
			  <a href='/search?facetcompany="{{ facility.title | replace({' ': '+'}) }}"'>{{ facility.title }}</a>
			  <span class="hide" aria-hidden=true> Office</span>
			</span>
			<span class="adr">
			  <span class="street-address">{{ facility.locationStreetAddress }}</span>
			  <span class="locality">{{ facility.locationCity }}</span>,
                          <span class="region">{{ facility.title }}</span> 
			  <span class="postal-code">{{ facility.locationZipCode }}</span>
			</span>
		     </article>
		   </li>
		 {% endfor %}
              </ol>
            </article>
	  </li>
	  {% endif %}
	  {% endfor %}
        </ol>
      </div>
    </div>
  </div>
  <div class="secondary-page-search">
    {% include "includes/_search-form.html" %}
  </div>
{% endblock %}

This is a great example of having to pivot once you better understand what your solution needs to address. I had made some wrong assumptions earlier in the project. And like a lot of projects, you don’t always know the number of locations from a client when you start working on a solution.

I think there also was a knowledge component when implementing the original solution that I lacked but gained by the time I revisited the problem. This new knowledge helped me to come up with a more robust solution that did not require manual sorting of a long list of entries.

Comments are closed.