Forum

Thread tagged as: Problem, Runway

Nested Collections

I'm trying to repeat data from a Runway Collection called "Properties" in a page template (a page template that is itself a detail page for a Collection named "Localities"). In that page template I have an edit-initializing <perch:related id="map-properties"> section higher up the page.

Farther down the page I need:

<section id="properties">
<perch:related id="map_properties" collection="Properties" scope-parent="true">
  <a href="/<perch:content id="parent.locality_slug" type="slug" />/<perch:content id="property_slug" type="slug" />/">
      <img src="<perch:content id="property_thumbnail" type="image" />" alt="<perch:content id="property_name" type="text" />">
    <h2><perch:content id="property_name" type="text" /></h2>
    <perch:content id="property_city" type="text" />, <perch:content id="property_state" type="text" />
  </a>
</perch:related>
</section>

My problem is with <perch:content id="property_state" type="text" /> because I'm trying to retrieve values from yet another Collection.

In my content, the geographic state needs to display sometimes as long-form ("Wisconsin") and sometimes as postal-coded ("WI").

I wanted a way to be able to retrieve either format via just one entry in the Properties editing form. Using a replace attribute with 51 patterns sounded like a bad idea, so I made a Collection named "States", templated elsewhere with two fields, state_full and state_code.

<perch:related id="property_state" collection="States">
<perch:content id="state_full" type="text" label="State Full Name" title="true" />
<perch:content id="state_code" type="text" label="State Postal Code" size="xs" format="UC" />
</perch:related>

So, going back to my Localities page (the top code block here), I've tried a number of approaches to getting that state name. Nesting <perch:related> tags doesn't return anything. The only thing that returns anything is this tag...

<perch:content id="property_state" type="text" />

...but it outputs a number instead of a value, which I presume is the array index of the State collection.

Is there a way to get the state_full value of that array?

Or am I just overcomplicating this? Is there a better, simpler way to solve my long-name-vs-postal-code issue other than having nested Collections?

Thanks for your input!

Joel Davies

Joel Davies 0 points

  • 4 years ago
Drew McLellan

Drew McLellan 2638 points
Perch Support

It does sound like you're overcomplicating things, but at this time of night I'm having trouble making head or tail of what's being asked.

Could you lay out what your collections are (in bullet point, not in prose) and how the relationships are set up?

Site structure:

Home
- Locality 1 (Collection)
-- Property A (Collection), located in U.S. State Z (Collection)
-- Property B (Collection), located in U.S. State Z (Collection)
- Locality 2 (Collection)
-- Property C (Collection), located in U.S. State Y (Collection)
-- Property D (Collection), located in U.S. State Y (Collection)

Locality Collection Template (stripped down):

<perch:content id="locality_name" type="smarttext" label="Locality Full Name" required="true" title="true" help="The full name of this locality used throughout the site" suppress="true" />
<perch:content id="locality_slug" type="slug" label="Slug" for="locality_name_short" editable="true" suppress="true" />
<--* START Properties Collection Relation *-->
<perch:related id="map_properties" collection="Properties" scope-parent="true" label="Properties in This Locality">
<a class="map-link" href="/<perch:content id="parent.locality_slug" type="slug" />/<perch:content id="property_slug" type="slug" />/"><perch:content id="property_name" type="text" /></a>
</perch:related>
<--* END Properties Collection Relation *-->

Property Collection Template (stripped down):

<perch:content id="property_name" type="smarttext" label="Property Full Name" required="true" title="true" help="The full name of this property used throughout the site" order="1" suppress="true" />
<perch:content id="property_slug" type="slug" label="Slug" for="property_name" editable="true" order="2" suppress="true" help="Do not change the Slug unless you know what you are doing! ;-)" required="true" />
<perch:content id="property_street_address" type="text" label="Property Street Address" required="true" order="4" />
<perch:content id="property_city" type="text" label="Property City" order="5" suppress="true" required="true" />
<--* START States Collection Relation *-->
<perch:related id="property_state" collection="States" order="6" label="Property State" help="Click to select a state. Select only one. State list is maintained in Collections." suppress="true" required="true"><perch:content id="state_full" /></perch:related>
<--* END States Collection Relation *-->
<perch:content id="property_zip" type="text" label="Property Zip Code" size="s" order="7" suppress="true" required="true" />

States Collection Template:

<perch:content id="state_full" type="text" label="State Full Name" required="true" title="true" help="Full name of the state" />
<perch:content id="state_code" type="text" label="State Postal Abbreviation" required="true" help="Two-letter postal code for the state" format="C:2" />

Goal is to render, on both Locality pages or Properties pages, navigational cards for the Properties in these formats:

property_name in property_city, state_full

OR

property_name property_street_address property_city, state_code property_zip

I wanted to set things up so the content editor only needed to fill out ONE field and in the template I could return either the full state name OR the state postal code as necessary. I thought making the States a collection might accomplish that.

Duncan Revell

Duncan Revell 78 points
Registered Developer

It looks to me as if you might be better served having your primary or master collection as Properties. So when you edit a property, you select which locality it is in - as opposed to what you currently have, which is to edit a locality and select which properties are in the locality.

The property can have two relationships - one to locality and one to state.

You can then run a query against your property collection and filter it by locality which would look something like:

perch_collection('Properties', [
    'filter' => 'locality.locality_slug',
    'match'  => 'eq',
    'value'  => 'A',
  ]);

You could then pass in a template to that query which would allow you get either state_full or state_short.

So you can still list all the properties per locality.

Further on, querying for all properties will only give you localities that have properties in them (because you're using the property as a "master"), but you could run a separate query on the Locality collection to get all the localities, should you need to.

Duncan, your suggestion makes a lot of sense. I wish I'd had that insight at the start: Properties are the meat of the site, Localities are just buckets. Here I was thinking I was about 95% done with the structure! To implement your idea, I assume I would have to:

  1. Remove <perch:related collection="Properties"> from my localities.html template
  2. Insert a <perch:related collection="Localities"> in my properties.html template
  3. Relink each Property to a Locality
  4. Adjust my localities.php and properties.php perch_collection() queries accordingly

Does that sound about right?

What would be the effects of those changes? Would it zero out the data in the Localities and Properties items I've already entered or would I just see the old Collection field disappear from my admin Localities form and a new Collection field appear in my Properties form? Do I need to somehow clear out the discarded Localities > Properties relational linkages in the db?

Duncan Revell

Duncan Revell 78 points
Registered Developer

Yeah that sounds about right.

I think the linkages are held in the collections index table - they will gradually disappear as more and more revisions (or saves) are made to the collections. I wouldn't worry too much about that.